在SICP中使用lambda作为cons / car / cdr定义

我刚刚开始觉得我对于在球拍和scheme中使用lambda有一个模糊的理解,当我在SICP中遇到以下“替代”缺陷和汽车的定义

(define (cons xy) (lambda (m) (mxy))) (define (car z) (z (lambda (pq) p))) (define (cdr z) (z (lambda (pq) q))) 

对于我的生活,我只是不能parsing它们。

任何人都可以解释如何parsing或扩展这些对于新手来说是有意义的吗?

这是一个有趣的方式来表示数据:作为function。 请注意,这个cons定义返回一个lambda ,它closures参数xy ,并在里面捕获它们的值。 另请注意,返回的lambda接收函数 m作为参数:

 ;creates a closure that "remembers' 2 values (define (cons xy) (lambda (m) (mxy))) ;recieves a cons holding 2 values, returning the 0th value (define (car z) (z (lambda (pq) p))) ;recieves a cons holding 2 values, returning the 1st value (define (cdr z) (z (lambda (pq) q))) 

在上面的代码中, z是一个闭包,与cons创build的一样,并且在过程的主体中,我们将另一个 lambda作为parameter passing给它,请记住m ? 就是这样! 它所期望的function。

了解以上情况,很容易看到carcar如何工作; 让我们一步一步剖析carcdr是如何被解释器评估的:

 ; lets say we started with a closure `cons`, passed in to `car` (car (cons 1 2)) ; the definition of `cons` is substituted in to `(cons 1 2)` resulting in: (car (lambda (m) (m 1 2))) ; substitute `car` with its definition ((lambda (m) (m 1 2)) (lambda (pq) p)) ; replace `m` with the passed parameter ((lambda (pq) p) 1 2) ; bind 1 to `p` and 2 to `q`, return p 1 

总结一下: cons创build一个“记住”两个值的闭包, car接收闭包并将其作为第零个值的select器传递, cdr充当第一个值的select器。这里是lambda作为一个闭包,这有多酷?我们只需要存储和检索任意数据的函数!

在大多数LISP中, carcdr嵌套组合被定义为4深 。 例:

 (define caddr (lambda (x) (car (cdr (cdr x))))) 

在我看来,最终的诀窍是从头到尾阅读定义,因为在这三个自由variables中,自由variables总是可以在体内的lambdaexpression式( mpq )中find的。 这是一个尝试将代码翻译成英文,从结尾(右下)到开头(左上):

 (define (cons xy) (lambda (m) (mxy)) 

无论m是什么,并且我们怀疑它是一个函数,因为它恰好出现在xy :它是xy的定义。

 (define (car z) (z (lambda (pq) q))) 

无论pq是什么,当应用z时, z是接受函数作为input的东西,则selectpq的第一个:这就是car的定义。

对于“接受函数作为input的东西”的例子,我们只需要回顾一下cons的定义。 所以,这意味着car接受cons作为其投入。

 (car (cons 1 2)) ; looks indeed familiar and reassuring (car (cons 1 (cons 2 '()))) ; is equivalent (car '(1 2)) ; is also equivalent (car z) ; if the previous two are equivalent, then z := '(1 2) 

最后一行表示:列表是“接受函数作为input的东西”。

不要让你的头在那一刻旋转! 该列表将只接受可以在列表元素上工作的函数。 而这正是因为我们重新定义了我们所拥有的方式。

我认为这个练习的主要观点是“计算是把操作和数据结合在一起,而不pipe你把它们放在一起的顺序如何”。

这应该很容易理解的组合符号(作为currying函数隐式转换为Scheme, fxy = z ==> (define f (λ (x) (λ (y) z))) ):

 cons xym = mxy car z = z _K ; _K pq = p cdr z = z (_K _I) ; _I x = x _K _I pq = _I q = q 

所以我们得到

 car (cons xy) = cons xy _K = _K xy = x cdr (cons xy) = cons xy (_K _I) = _K _I xy = _I y = y 

所以定义做我们所期望的。 简单

在英语中, cons xy值是一个函数,表示“如果你给我一个两个参数的函数,我将用我持有的两个参数来调用它,然后让它决定如何处理它们!”

换句话说,它期望一个“继续”的function,并用它的(“对”)创build中使用的两个参数来调用它。