Scheme 理解教堂数字

Scheme 理解教堂数字,scheme,lisp,sicp,church-encoding,Scheme,Lisp,Sicp,Church Encoding,我正在研究SICP,它给出了教堂数字的zero的以下定义: 关于这一点,我有几个问题: 为什么语法这么复杂?它似乎很容易阅读,只需使用以下内容即可: (define (zero f) (lambda (x) x)) 我们可以看到,这是一个名为zero的函数,它接受一个(未使用的)参数f,并返回一个包含一个参数的函数,该参数将返回其参数。这个定义似乎只是尽可能不直截了当 有什么用的?例如,做如下事情: ((zero square) 100) 返回100。x是否只是返回的默认值 (l

我正在研究SICP,它给出了教堂数字的
zero
的以下定义:

关于这一点,我有几个问题:

  • 为什么语法这么复杂?它似乎很容易阅读,只需使用以下内容即可:

    (define (zero f) 
       (lambda (x) x))
    
    我们可以看到,这是一个名为
    zero
    的函数,它接受一个(未使用的)参数
    f
    ,并返回一个包含一个参数的函数,该参数将返回其参数。这个定义似乎只是尽可能不直截了当

  • 有什么用的?例如,做如下事情:

    ((zero square) 100)
    
    返回
    100
    x
    是否只是返回的默认值


  • (lambda(x)x)
    中没有
    x
    。没有

    (lambda(x)x)
    中的
    x
    已绑定。它可以用任何名字命名。我们不能在
    (lambda(x)x)
    中谈论
    x
    ,正如我们不能在
    (lambda(y)y)
    中谈论
    y
    一样

    (lambda(y)y)
    中没有
    y
    。它只是一个占位符,一个任意的名称,它在正文中的唯一用途是与活页夹中的相同。同样,不考虑使用哪一个特定名称,只要使用两次——第一次在活页夹中,另一次在正文中

    事实上,对于lambda术语,还有另一个完整的符号,叫做De Bruijn符号,在这里,同样的东西被写成
    (lambda 1)
    1
    的意思是“我指的是我上面的活页夹1步收到的参数”

    所以
    x
    并不重要。重要的是
    (lambda(x)x)
    ,它表示按原样返回参数的函数。所谓的“身份”功能

    但这在这里并不重要。数字的Church编码实际上是一个二进制函数,该函数需要两个参数--
    f
    z
    。“后继步骤”一元函数
    f
    和“零”值
    z
    ,不管是什么,只要两者同时存在。一起讲道理。一起工作

    那么,当一个二元函数在起作用时,我们怎么会看到两个一元函数呢

    这是重要的一点。它被称为“咖喱”

    在lambda演算中,所有函数都是一元函数。为了表示一个二元函数,使用了一元函数,当给出它的(第一个)参数时,它返回另一个一元函数,当给出它的(现在,第二个)参数时,它执行我们想要的二元函数应该执行的任何事情,使用这两个参数,第一个和第二个

    如果我们用组合(等式)表示法而不是lambda表示法来写,这一切都非常简单:

    zero f z = z
    one f z = f z
    two f z = f (f z) = f (one f z) = succ one f z
    succ one f z = f (one f z)
    
    其中,每个并置表示一个应用程序,所有应用程序都在左侧关联,因此我们设想上面的符号是

    zero f = lambda z. z
    zero = lambda f. (lambda z. z)
    ......
    ......
    succ = lambda one. (lambda f. (lambda z. f (one f z) ))
    ;; such that
    succ one f z = (((succ one) f) z)
      = ((((lambda one. (lambda f. (lambda z. f (one f z) ))) one) f) z)
      = .... 
      = (f ((one f) z))
      =  f (one f z)
    
    但这是一样的。符号的不同并不重要

    当然,
    lambda one中没有
    one
    。(λf.(λz.f(一个f z)))
    。这是必然的。我不知道,它可以命名为,
    number

    也就是说,
    (成功编号)
    就是这样一个编号,给定
    f
    z
    ,与
    number
    相比,它会对它们执行一个以上的
    f
    步骤


    因此,
    ((零平方)100)
    意味着,将数字
    zero
    与后续步骤
    square
    100
    的零值一起使用,并让
    zero
    为我们执行后续步骤的数量——也就是说,0步——从零值开始。因此原封不动地退回

    另一种可能的用法是
    ((零(λ(x)0))1)
    ,或一般用法

    ((lambda (n) ((n (lambda (x) 0)) 1)) zero)  
    
    ;; or even more generally, abstracting away the 0 and the 1,
    
    ((((lambda (n) (lambda (t) (lambda (f) ((n (lambda (x) f)) t)))) zero) 1) 0)
    
    这只是另一种写作方式

    zero (lambda x. 0) 1  ;; or
    
    foo n t f = n (lambda x. f) t   ;; and calling
    
    foo zero 1 0
    

    希望您可以轻松地看到
    foo
    是什么。以及如何大声朗读这个
    t
    和这个
    f
    。(可能原始的
    f
    最好命名为
    s
    ,以表示“继任者”或类似的名称)。

    中没有
    x
    (lambda(x)x)
    。没有

    (lambda(x)x)
    中的
    x
    已绑定。它可以用任何名字命名。我们不能在
    (lambda(x)x)
    中谈论
    x
    ,正如我们不能在
    (lambda(y)y)
    中谈论
    y
    一样

    (lambda(y)y)
    中没有
    y
    。它只是一个占位符,一个任意的名称,它在正文中的唯一用途是与活页夹中的相同。同样,不考虑使用哪一个特定名称,只要使用两次——第一次在活页夹中,另一次在正文中

    事实上,对于lambda术语,还有另一个完整的符号,叫做De Bruijn符号,在这里,同样的东西被写成
    (lambda 1)
    1
    的意思是“我指的是我上面的活页夹1步收到的参数”

    所以
    x
    并不重要。重要的是
    (lambda(x)x)
    ,它表示按原样返回参数的函数。所谓的“身份”功能

    但这在这里并不重要。数字的Church编码实际上是一个二进制函数,该函数需要两个参数--
    f
    z
    。“后继步骤”一元函数
    f
    和“零”值
    z
    ,不管是什么,只要两者同时存在。一起讲道理。一起工作

    那么,当一个二元函数在起作用时,我们怎么会看到两个一元函数呢

    这是重要的一点。它被称为“咖喱”

    在lambda演算中,所有函数都是一元函数。表示二元函数的一元函数是
    ((lambda (n) ((n (lambda (x) 0)) 1)) zero)  
    
    ;; or even more generally, abstracting away the 0 and the 1,
    
    ((((lambda (n) (lambda (t) (lambda (f) ((n (lambda (x) f)) t)))) zero) 1) 0)
    
    zero (lambda x. 0) 1  ;; or
    
    foo n t f = n (lambda x. f) t   ;; and calling
    
    foo zero 1 0