Когда программа сообщает let v = expr1 in expr2
, OCaml сначала оценивает expr1
, а затем начинает оценку expr2
в среде, в которой v
связано со значением, полученным в результате expr1
.
Эта стратегия оценки, call-by-value , не единственно возможная, но это стратегия, которую использует OCaml.
Теперь давайте рассмотрим фрагмент:
let rec some_function = function ...
in
let s = (*some list*)
some_function s
Когда программа содержит фрагмент выше, выполняются следующие шаги:
function ...
.Этот шаг короткий, потому что оценка блока function ...
не означает, что код внутри ...
оценивается.Вместо этого результат оценки function ...
является закрытием (забывая об оптимизациях, которые применяются в вашем примере, но не в целом). - код, представленный
(*some list*)
, оценивается в среде, в которой some_function
связано с замыканием, обсужденным выше. - выражение
some_function s
вычисляется в среде, где some_function
связано с замыканием, а s
связано с результатом оценки (*some list*)
.В этой среде эта оценка завершается успешно и применяется замыкание, что означает, что код, который определил some_function
, теперь будет выполняться (в среде, где указан его аргумент).
Замыканиесостоит из недооцененного кода и частичной среды.Среду нужно только дополнить дополнительным связыванием для аргумента, чтобы он содержал все необходимое для оценки кода.С другой стороны, пока аргумент не был предоставлен, оценка не может начаться, потому что тело функции ссылается на аргумент.
Тот факт, что some_function
является рекурсивным, не меняет общую схему.Это означает только то, что при оценке тела замыкания среда также содержит привязку, связывающую тот же some_function
с замыканием, так что вызов some_closure
внутри тела обрабатывается так же, как и внекорпус.