我试图学习lambda演算和Scheme Lisp。有关lambda演算的教程可以在http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf找到。
我面临的问题是我不知道如何正确实现迭代。
(define (Y y) (((lambda (x) (y (x x))) (lambda (x) (y (x x))))))
(define (sum r n) ((is_zero n) n0 (n succ (r (pred n)))))
(display ((Y sum) n5))
我总是收到这个错误:
中止!:超出最大递归深度
我知道问题与评估顺序有关:该方案首先解释(Y sum)
,这导致无限递归:
((Y sum) n5) -> (sum (Y sum) n5) -> ((sum (sum (Y sum))) n5) -> .... (infinite recursion)
但我想要
((Y sum) n5) -> ((sum (Y sum) n5) -> (n5 succ ((Y sum) n4)) -> .... (finite recursion)
我该如何解决这个问题?感谢。
答案 0 :(得分:1)
延迟计算的标准方法是通过eta-expansion:
(define (Y y) ((lambda (x) (y (x x))) (lambda (x) (y (x x) )) ))
=~
(define (YC y) ((lambda (x) (y (lambda (z) ((x x) z))))
(lambda (x) (y (lambda (z) ((x x) z)))) ))
因此
((YC sum) n5)
=
(let* ((y sum)
(x (lambda (x) (y (lambda (z) ((x x) z)))) ))
((y (lambda (z) ((x x) z))) n5))
=
(let ((x (lambda (x) (sum (lambda (z) ((x x) z)))) ))
((sum (lambda (z) ((x x) z))) n5))
=
...
并评估(sum (lambda (z) ((x x) z)))
只是使用 包含自我应用程序的lambda函数,但尚未调用它。
扩张将达到目的
(n5 succ ((lambda (z) ((x x) z)) n4))
=
(n5 succ ((x x) n4)) where x = (lambda (x) (sum (lambda (z) ((x x) z))))
并且仅在那时将执行自我应用。
因此,(YC sum)
= (sum (lambda (z) ((YC sum) z)))
,而不是分歧(在评估的适用顺序下)(Y sum)
= { {1}}。
答案 1 :(得分:1)
Lambda演算是一种正常的订单评估语言。因此,它与Haskell有更多共同之处,而Scheme是一种应用顺序评估语言。
在DrRacket中你有一个方言#lang lazy
,它与你得到的方案一样接近,但是因为它很懒,你有正常的订单评估:
#!lang lazy
(define (Y f)
((lambda (x) (x x))
(lambda (x) (f (x x)))))
(define sum
(Y (lambda (r)
(lambda (n)
((is_zero n) n0 (n succ (r (pred n))))))))
(church->number (sum n5))
如果您无法更改语言,可以将其包装在lambda中以使其延迟。例如
如果r
是arity 1的函数,lambda演算中的所有函数都是,那么(lambda (x) (r x))
是r
的完全正确的重构。它将停止infitie递归,因为你只获得包装器,它只在你每次递归时都应用它,即使评估是急切的。急切语言的Y组合称为Z:
(define (Z f)
((lambda (x) (x x))
(lambda (x) (f (lambda (d) ((x x) d))))))
如果你想在Scheme中做Z,例如使用多个参数递归函数,你可以使用rest参数:
(define (Z f)
((lambda (x) (x x))
(lambda (x) (f (lambda args (apply (x x) args))))))
((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