方案中的 Y 组合器使用教会数字会爆炸,但适用于常规数字
Y combinator in scheme blows up using Church numbers, but works on regular numbers
我刚刚阅读了 Raul Rojas 的“Lambda 微积分教程介绍1”。我把lambda表达式放到Scheme(TinyScheme)中试试看。除了使用内存不足的 Y 组合器计算教会数字 0,1,...,N 之和的递归函数外,一切正常。奇怪的是,如果我使用常规数字计算总和,Y 组合器会起作用。
这是我的 Y 组合器,
(define myY
(lambda (y)
((lambda (x) (x x))
(lambda (x)
(y (lambda (a) ((x x) a)))))))
这里是一个递归函数,求N个正则数之和,
(define sum1
(lambda (r)
(lambda (x)
(cond
((zero? x) 0)
(else (+ x (r (sub1 x))))))))
这个有效
> ((myY sum1) 10)
55
在教程第15页的底部,递归函数R=Lrx.Zx0(NS(r(PN)))用于计算N个数的和(L=lambda)。在这个表达式中,r 将是递归函数,x 将是一个丘奇数,Z 是零函数的测试,0 是一个零作为一个丘奇数,N 是一个丘奇数,S 是后继函数,P 是前置函数。我已将其翻译成 Scheme 为,
(define myR
(lambda (r)
(lambda (x)
(((myZ x) my0) ((x myS) (r (myP x))))
)))
然而,即使取 0 个数的和也会爆炸。
> ((((myY myR) my0) add1) 0)
No memory!
在上一行中,((myY myR) my0) 应该 return 教堂编号为零。我只是让教堂编号作用于 add1 以获得人类可读的教堂编号。
最初,我认为 Y 组合器是问题所在,但是,正如我所展示的,这适用于使用常规数字的递归函数。 Church 数在教程中定义,lambda 表达式的 Scheme 版本适用于算术(加法、乘法、不等式)。
编辑:
函数 myZ 是 lambda 表达式 Z=Lx.xF¬F,其中 F=Lxy.y 为假(真为 T=Lxy.x)并且 ¬=Lx.xFT 不是。函数 Z 执行条件测试,因为 Z0=T 和 ZN=F,其中 0 是零的教会数 (0=Lxy.y),N 是非零的教会数 (1=Lxy.xy , 2=Lxy.x(xy) etc.) 实现Z的Scheme代码myZ是,
(define myZ
(lambda (x)
(((x myF) myNeg) myF)
))
lambda 演算仅适用于正常的降序(即仅在需要其值时才评估参数),而 Scheme 使用应用降序(首先评估参数),“特殊形式”除外。
您的代码使用常规数字不是因为数字,而是因为 cond
,它将最多评估其子句之一。
如果您将 sum1
中的 cond
替换为常规函数,您的计算也不会以常规数字终止。
; This does not work
(define (conditional b t e)
(if b t e))
(define sum1
(lambda (r)
(lambda (x)
(conditional
(zero? x)
0
(+ x (r (sub1 x)))))))
您可以通过添加一个间接级别来解决这个问题;通过将它们包装在函数中来暂停对分支的评估:
(define sum1
(lambda (r)
(lambda (x)
((conditional
(zero? x)
(lambda (y) 0)
(lambda (y) (+ x (r (sub1 x)))))
"some argument"))))
相应的转换将在您的实施中起作用。
我刚刚阅读了 Raul Rojas 的“Lambda 微积分教程介绍1”。我把lambda表达式放到Scheme(TinyScheme)中试试看。除了使用内存不足的 Y 组合器计算教会数字 0,1,...,N 之和的递归函数外,一切正常。奇怪的是,如果我使用常规数字计算总和,Y 组合器会起作用。
这是我的 Y 组合器,
(define myY
(lambda (y)
((lambda (x) (x x))
(lambda (x)
(y (lambda (a) ((x x) a)))))))
这里是一个递归函数,求N个正则数之和,
(define sum1
(lambda (r)
(lambda (x)
(cond
((zero? x) 0)
(else (+ x (r (sub1 x))))))))
这个有效
> ((myY sum1) 10)
55
在教程第15页的底部,递归函数R=Lrx.Zx0(NS(r(PN)))用于计算N个数的和(L=lambda)。在这个表达式中,r 将是递归函数,x 将是一个丘奇数,Z 是零函数的测试,0 是一个零作为一个丘奇数,N 是一个丘奇数,S 是后继函数,P 是前置函数。我已将其翻译成 Scheme 为,
(define myR
(lambda (r)
(lambda (x)
(((myZ x) my0) ((x myS) (r (myP x))))
)))
然而,即使取 0 个数的和也会爆炸。
> ((((myY myR) my0) add1) 0)
No memory!
在上一行中,((myY myR) my0) 应该 return 教堂编号为零。我只是让教堂编号作用于 add1 以获得人类可读的教堂编号。
最初,我认为 Y 组合器是问题所在,但是,正如我所展示的,这适用于使用常规数字的递归函数。 Church 数在教程中定义,lambda 表达式的 Scheme 版本适用于算术(加法、乘法、不等式)。
编辑: 函数 myZ 是 lambda 表达式 Z=Lx.xF¬F,其中 F=Lxy.y 为假(真为 T=Lxy.x)并且 ¬=Lx.xFT 不是。函数 Z 执行条件测试,因为 Z0=T 和 ZN=F,其中 0 是零的教会数 (0=Lxy.y),N 是非零的教会数 (1=Lxy.xy , 2=Lxy.x(xy) etc.) 实现Z的Scheme代码myZ是,
(define myZ
(lambda (x)
(((x myF) myNeg) myF)
))
lambda 演算仅适用于正常的降序(即仅在需要其值时才评估参数),而 Scheme 使用应用降序(首先评估参数),“特殊形式”除外。
您的代码使用常规数字不是因为数字,而是因为 cond
,它将最多评估其子句之一。
如果您将 sum1
中的 cond
替换为常规函数,您的计算也不会以常规数字终止。
; This does not work
(define (conditional b t e)
(if b t e))
(define sum1
(lambda (r)
(lambda (x)
(conditional
(zero? x)
0
(+ x (r (sub1 x)))))))
您可以通过添加一个间接级别来解决这个问题;通过将它们包装在函数中来暂停对分支的评估:
(define sum1
(lambda (r)
(lambda (x)
((conditional
(zero? x)
(lambda (y) 0)
(lambda (y) (+ x (r (sub1 x)))))
"some argument"))))
相应的转换将在您的实施中起作用。