На ленивом языке, таком как Lazy Racket, вы можете использовать обычную версию заказа, но не на любом языке программирования прикладного порядка, таком как Scheme. Они просто перейдут в бесконечный цикл.
аппликативном версия Y часто называют Z комбинатор:
(define Z
(lambda (f)
((lambda (g) (g g))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
Теперь первое, что происходит, когда это применяется в (g g)
и так как вы всегда можете заменить целое приложение с расширением его тела тело функции можно переписать на:
(define Z
(lambda (f)
((lambda (g)
(f (lambda args (apply (g g) args))))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
Я ничего не изменил. Это всего лишь немного больше кода, который делает то же самое. Обратите внимание, что эта версия использует apply
для поддержки нескольких функций аргументов. Представьте себе функцию Аккермана:
(define ackermann
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1)))))))
(ackermann 3 6) ; ==> 509
Это может быть сделано с Z
так:
((Z (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
Обратите внимание, что реализация точно так же, и разница, как обрабатывается ссылка на себя.
EDIT
Итак, вы спрашиваете, как оценка получает с задержкой. Ну нормальная версия заказа выглядит следующим образом:
(define Y
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (g g))))))
Если посмотреть на то, как это будет применяться с аргументом, вы заметите, что Y никогда не возвращается, так как прежде чем он сможет применить f
в (f (g g))
он должен оценить (g g)
, которые в свою очередь оценивает (f (g g))
и т. д. Для спасения мы не применяем (g g)
сразу. Мы знаем, что (g g)
становится функцией, поэтому мы просто даем f
функцию, которая при применении генерирует фактическую функцию и применяет ее. Если у вас есть функция add1
, вы можете сделать обертку (lambda (x) (add1 x))
, которую вы можете использовать, и она будет работать. Точно так же (lambda args (apply (g g) args))
- это то же самое, что и (g g)
, и вы можете видеть это, просто применяя правила замещения. Ключ здесь заключается в том, что это фактически останавливает вычисление на каждом шаге, пока оно фактически не будет использовано.
Вы не можете, потому что традиционный комбинатор Y не работает с оценкой прикладного заказа. – user2357112
Версия 'Y ≡ (λy. (Λx.y (xx)) (λx.y (xx)))' предполагает ленивую оценку.Один из способов отсрочить оценку функции - обернуть выражение функции 'e' в' (lambda (arg) (e arg)) ', поэтому в этом случае выражение функции' (процедура процедуры) 'переписывается как' (lambda (arg) ((процедура процедуры) arg)) '. –
@AlexKnauth Так что, если у меня есть рекурсивная функция сложения, чтобы добавить от 0 до п чисел, как это: '(определяют (REC итерации процедуры) \t ( \t \t итерации (ISZERO) \t \t \t (+ итерации (процедура (- итерации 1))) \t) ) ' Как использовать это с Y-combinator в схеме.? –