在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参数x
和y
,并在里面捕获它们的值。 另请注意,返回的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。
了解以上情况,很容易看到car
和car
如何工作; 让我们一步一步剖析car
, cdr
是如何被解释器评估的:
; 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中, car
& cdr
嵌套组合被定义为4深 。 例:
(define caddr (lambda (x) (car (cdr (cdr x)))))
在我看来,最终的诀窍是从头到尾阅读定义,因为在这三个自由variables中,自由variables总是可以在体内的lambdaexpression式( m
, p
和q
)中find的。 这是一个尝试将代码翻译成英文,从结尾(右下)到开头(左上):
(define (cons xy) (lambda (m) (mxy))
无论
m
是什么,并且我们怀疑它是一个函数,因为它恰好出现在x
和y
:它是x
和y
的定义。
(define (car z) (z (lambda (pq) q)))
无论
p
和q
是什么,当应用z
时,z
是接受函数作为input的东西,则selectp
和q
的第一个:这就是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中使用的两个参数来调用它。