Пример немного тонкий, потому что он не использует обычные продолжения, а вместо этого строит структуру, которая может быть оценена шаг за шагом. В месте, где вы обычно делаете рекурсивный вызов, он возвращает значение Step
, которое содержит функцию, которую вы (рекурсивно) вызываете.
Во втором случае функция linearize
возвращает Step
, содержащую функцию, которая будет вызывать linearize
рекурсивно, но она не немедленно делает рекурсивный вызов. Таким образом, функция не выполняет рекурсивный вызов (она просто сохраняет рекурсивную ссылку).
Имеет смысл рассмотреть вопрос о том, является ли программа хвостовой рекурсивной, когда вы смотрите на processSteps
, потому что она выполняет реальный цикл - и это хвостовая рекурсивность, потому что она запускает Step
на Step
без сохранение стекового пространства для каждого Step
.
Если вы хотите создать список вместо цепочки ленивых шагов, вам придется сделать рекурсивный вызов linearize
непосредственно внутри продолжения:
let rec linearize binTree cont =
match binTree with
| Empty -> cont []
| Node(x, l, r) ->
linearize l (fun l -> linearize r (fun v -> cont (x::v)))
По сути, это то же самое, что и предыдущая функция, но на самом деле она вызывает linearize
вместо построения Step
, содержащей функцию, которая будет вызывать linearize
.