方案中的 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"))))

相应的转换将在您的实施中起作用。