【问题标题】:Understanding church numerals了解教会数字
【发布时间】:2021-05-13 22:24:17
【问题描述】:

我正在通过 SICP 工作,它为 Church Numerals 给出了 zero 的以下定义:

(define zero (lambda (f) (lambda (x) x)))

对此我有几个问题:

  1. 为什么语法复杂?只需使用以下内容,它似乎就很易读了:

    (define (zero f) 
       (lambda (x) x))
    

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

  2. x 有什么用?例如做类似的事情:

    ((zero square) 100)
    

    返回100x 只是返回的默认值吗?

【问题讨论】:

  • 教会数字来自一种叫做 Lambda Calculus 的东西。所以这本书只是通过到处使用 lambdas 来明确它们的起源。您应该尝试阅读有关教堂数字的信息,维基百科有一个不错的条目en.wikipedia.org/wiki/Church_encoding#Church_numerals
  • 这个练习的重点是解决它向你展示了 Church 编码是多么奇怪而美妙的想法。

标签: scheme lisp sicp church-encoding


【解决方案1】:

(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 步的 binder 收到的论点”。

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

但即使这在这里也不重要。数字的 Church 编码实际上是一个二进制函数,一个需要两个参数的函数——fz。 “后继步骤”一元函数f 和“零”“值”z,不管是什么,只要两者结合在一起。一起有意义。一起工作。

那么,当它实际上是一个二元函数时,我们怎么会看到两个一元函数呢?

是重要的一点。它被称为 currying

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

如果我们只是用组合(等式)表示法而不是 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. (lambda f. (lambda z. f (one f z) )) 中没有one。它是绑定的。它可能只是被命名,我不知道,number

succ number f z = f (number f z) = f ((number f) z)

意思是,(succ number) 就是这样一个数字,考虑到fz,与number 相比,f 会多出一个步骤.


因此,((zero square) 100) 的意思是,使用数字 zero 与后继步骤 square 和零值 100,并让 zero 为我们执行其后继步骤数量 - 即也就是说,0 步——从零值开始。因此原样返回。

另一个可能的用法是((zero (lambda (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,用于“继任者”或类似的名称)。

【讨论】:

    猜你喜欢
    • 2011-04-24
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多