2014-02-13 3 views
4

Я работаю свой путь через F # Wikibook и я попал в секцию на опорных ячеек, в котором появляется следующий фрагмент кода:Инкапсуляция изменяемые состояния

let incr = 
    let counter = ref 0 
    fun() -> 
     counter := !counter + 1 
     !counter;; 

Эта функция затем вызывается в три раза, давая значения 1, 2 и 3 соответственно. Может кто-нибудь объяснить, почему эта функция не возвращает 1 при каждом ее вызове? То, как я интерпретирую этот код (что, очевидно, не является правильной интерпретацией, следовательно, вопросом), состоит в том, что во-первых объявляется счетчик опорных ячеек с содержимым, равным 0, тогда содержимое «счетчика» увеличивается на 1 а затем разыменовывается с помощью анонимной функции. Поскольку каждый вызов incr();; объявляет «счетчик» с содержимым 0, я не понимаю, почему вызов incr();; не просто возвращает 1 каждый раз.

Может ли кто-нибудь исправить мое понимание?

Заранее спасибо.

ответ

6

Подумайте об этом так: incr - значение, а не функция. Его значение представляет собой замыкание, которое фиксирует некоторое состояние (то есть counter). Это закрытие, которое впоследствии вызывается потенциально несколько раз (incr выполняется только один раз). Может быть, увидеть эквивалент C# поможет.

static Func<int> MakeCounter() { 
    int counter = 0; 
    return() => { 
     counter++; 
     return counter; 
    }; 
} 

var incr = MakeCounter(); 
incr(); //1 
incr(); //2 
incr(); //3 
+0

Интересно отметить, что вы можете захватить изменяемую переменную 'counter' в закрытии C#, тогда как вам нужно явно сделать' counter' ячейку, выделенную кучей в F #. –

+1

@JohnReynolds См. Запись в блоге здесь: http://lorgonblog.wordpress.com/2008/11/12/on-lambdas-capture-and-mutability/ С помощью изменяемой переменной таким образом иногда бывает сложно рассуждать. Принуждение к использованию контрольной ячейки делает более понятным, что происходит. – mydogisbox

3

При вызове incr() вы вызываете значение incr которое является анонимной функцией на линии 3. Код, который вызывается является только анонимной функцией, не все строк в определении incr.

Инициализация counter выполняется только один раз, когда incr определен, а не каждый раз, когда вызывается значение incr.

3

«incr» - это значение, а не функция. Он создает экземпляр «счетчика», а затем привязывается к внутренней функции (которая закрывает «счетчик»)

Вызов 'incr' действительно вызывает внутреннюю функцию. «counter» только объявляется и создается один раз.

Смежные вопросы