Я хочу Функция, которая хранит локальное состояние в Ruby.
Это слово «функция» должно немедленно поднять большой красный красный предупреждающий знак, что вы используете неправильный язык программирования. Если вы хотите функции, вы должны использовать функциональный язык программирования, а не объектно-ориентированный один.В функциональном языке программирования, функции, как правило, близки по их лексической среде, что делает то, что вы пытаетесь сделать абсолютно тривиальным:
var state;
function incMult(factor) {
if (state === undefined) {
state = 0;
}
state += 1;
return factor * state;
}
print(incMult(2)); // => 2
print(incMult(2)); // => 4
print(incMult(2)); // => 6
Этот конкретный пример в ECMAScript, но он выглядит более или менее то же самое в любой функциональный язык программирования.
[Примечание: я знаю, что это не очень хороший пример, потому что ECMAScript на самом деле также является объектно-ориентированным языком и потому, что он нарушил семантику семантики, что в корне означает, что в этом случае также утечка state
. На языке с правильной семантикой области (и через пару лет ECMAScript будет одним из них), это будет работать по назначению. Я использовал ECMAScript главным образом для его знакомого синтаксиса, а не как пример хорошего функционального языка.]
Это то, как состояние инкапсулировано в функциональные языки, поскольку, так как есть функциональные языки, все пути назад лямбда-исчисление.
Однако в 1960-е годы некоторые умные люди заметили, что это был очень распространенный образец, и они решили, что этот шаблон был , поэтому общий, что он заслуживает своей собственной языковой функции. И таким образом, появился объект.
Итак, в объектно-ориентированном языке вместо использования функциональных замыканий для инкапсуляции состояния вы должны использовать объекты. Как вы могли заметить, методы в Ruby не закрывают лексическую среду, в отличие от функций в языках функционального программирования. И это именно причина: потому что инкапсуляция состояния достигается другими средствами.
Так, в Ruby, вы бы использовать объект, как это:
inc_mult = Object.new
def inc_mult.call(factor)
@state ||= 0
@state += 1
factor * @state
end
p inc_mult.(2) # => 2
p inc_mult.(2) # => 4
p inc_mult.(2) # => 6
[Sidenote: Это 1: 1 соответствие то, что функциональные программисты говорят о том, когда они говорят, что «объекты являются только закрытие бедного человека» , Конечно, объектно-ориентированные программисты обычно сталкиваются с «закрытием - это всего лишь объекты бедного человека». И самое смешное, оба они правы, и никто из них не осознает этого.]
Теперь, для полноты я хочу отметить, что, хотя методы не закрываются по их лексической среде, существует одна конструкция в Ruby, который делает: блоки. (Интересно, что блоки не являются объектами.) И, так как вы можете определить методы с использованием блоков, вы можете также определить методы, которые являются укупорочные:
foo = Object.new
state = nil
foo.define_singleton_method :inc_mult do |factor|
state ||= 0
state += 1
factor * state
end
p foo.inc_mult(2) # => 2
p foo.inc_mult(2) # => 4
p foo.inc_mult(2) # => 6
Я не слишком хорошо знакомы с ними, но ISN» Это продолжение? Я бы заглянул в 'callcc' для получения дополнительной информации. –