Scheme 教会数字算术
我正在通过SICP工作,这让我有些进退两难。在处理教会数字时,将零和1编码为满足某些公理的任意函数的概念似乎是有道理的。此外,使用零的定义和add-1函数推导单个数字的直接公式是有意义的。我不明白加号运算符是如何形成的 到目前为止,我有这个Scheme 教会数字算术,scheme,sicp,lambda-calculus,church-encoding,Scheme,Sicp,Lambda Calculus,Church Encoding,我正在通过SICP工作,这让我有些进退两难。在处理教会数字时,将零和1编码为满足某些公理的任意函数的概念似乎是有道理的。此外,使用零的定义和add-1函数推导单个数字的直接公式是有意义的。我不明白加号运算符是如何形成的 到目前为止,我有这个 (define zero (lambda (f) (lambda (x) x))) (define (add-1 n) (lambda (f) (lambda (x) (f ((n f) x))))) (define one (lambda (f) (
(define zero (lambda (f) (lambda (x) x)))
(define (add-1 n)
(lambda (f) (lambda (x) (f ((n f) x)))))
(define one (lambda (f) (lambda (x) (f x))))
(define two (lambda (f) (lambda (x) (f (f x)))))
通过查看维基百科条目,我发现plus的定义是plus:=λmnfx.mf(nfx)。根据这个定义,我可以制定以下程序
(define (plus n m)
(lambda (f) (lambda (x) ((m f) ((n f) x)))))
我不明白的是,如何仅使用先前导出的过程提供的信息直接导出该过程。有人能以某种严格的证明形式回答这个问题吗?直觉上,我认为我理解正在发生的事情,但正如理查德·费曼(Richard Feynman)曾经说过的,“如果我不能构建它,我就无法理解它……”其实很简单。这可能会被视为是一种诱饵,但帕伦人让人更难看到——更好的方法是想象你使用的是一种咖喱语,或者仅仅使用Scheme具有多参数函数的事实并接受它。。。下面是一个使用lambdas和多参数的解释:
- 每个数字N被编码为
(lambda (f x) ...apply (f (f (f ... (f x)))) N times...)
(lambda (f) f^N)
- 这意味着N的编码实际上是
其中(lambda (f x) (f^N x))
是函数求幂f^N
- 一种更简单的方法(假设使用curry):数字N被编码为
(lambda (f x) ...apply (f (f (f ... (f x)))) N times...)
所以N实际上是一个“提升到N的幂”函数(lambda (f) f^N)
- 现在使用您的表达式(查看此处的
s): 因为lambda
是一个数字的编码,它是指数运算,所以这实际上是:n
对于((m f) (f^n x))
,也一样:m
剩下的应该是显而易见的。。。您已将(f^m (f^n x))
的m
应用于f
的n
应用于f
x
- 最后,留下一些乐趣——这里有另一种定义
的方法:plus
(嗯,没有太多乐趣,因为这一点可能更明显。)(define plus (lambda (m) (lambda (n) ((m add1) n))))
#apply
程序,我认为作者并不打算让学生了解这一点或咖喱等概念来回答这个问题
他们几乎是通过建议一个人应用替代方法来引导一个人找到答案,然后从那里我们应该注意到加法的效果是一个数字与另一个数字的组合。作文是练习1.42中引入的一个概念;这就是理解加法程序如何在这个系统中工作所需要的全部内容
; The effect of procedure #add-1 on `one`, and `two` was the composition of `f`
; onto `one` and `f` onto `two`.
;
; one : (λ (f) (λ (x) (f x)))
; two : (λ (f) (λ (x) (f (f x))))
; three : (λ (f) (λ (x) (f (f (f x)))))
;
; Thus one may surmise from this that an additive procedure in this system would
; work by composing one number onto the other.
;
; From exercise 1.42 you should already have a procedure called #compose.
;
; With a little trial and error (or just plain be able to see it) you get the
; following solution.
(define (adder n m)
(λ (f)
(let ((nf (n f))
(mf (m f)))
(compose nf mf))))
(确保你理解)。在的中,函数是唯一的基元数据类型。没有数字、布尔、列表或其他任何东西,只有函数。函数只能有一个参数,但函数可以接受和/或返回函数,而不是这些函数的值,而是函数本身。因此,要表示数字、布尔值、列表和其他类型的数据,必须想出一种聪明的方法,让匿名函数代表它们。是代表的方式。非类型化lambda演算中最原始的三个构造是:
λx.x
,一个函数,接受某个函数并立即返回它λx.x x
,自行应用λf.λx.f x
,函数应用,获取函数和参数,并将函数应用于参数f(f(fx))
。让我们用lambda演算对其进行编码:
- 0=
λf.λx.x
- 1=
λf.λx.fx
- 2=
λf.λx.f(fx)
- 3=
λf.λx.f(f(f x))
λf.λx.
开头,并且在有限次重复应用f之后,因此我们需要以某种方式进入λf.λx.
的主体,并将其包装成另一个f
。如何在不减少的情况下更改抽象体?那么,您可以应用一个函数,将主体包装在一个函数中,然后将新主体包装到旧的lambda抽象中。但是您不希望参数改变,因此您将抽象应用于同名的值:((λf.λx.f x)f)x→ f x
,但((λf.λx.f x)a)b)→ a b
,这不是我们需要的
这就是为什么add1
是λn.λf.λx.f((nf)x)
:将n
应用于f
,然后x
将表达式减少到主体,然后将f
应用到该主体,然后用λf.λx.
再次提取它练习:也要看到这是真的,快速学习并减少(λn.λf.λx.f((nf)x))(λf.λx.f(fx))
以1增加2
现在理解了将主体包装到另一个函数调用中的直觉,我们如何实现2个数字的加法?我们需要一个函数,给定λf.λx.f(fx)
(2)和λf.λx.f(fx))
(3),它将返回λf.λx.f(f(fx))
(5)。看2。如果你能把它换掉呢<