【发布时间】:2014-10-22 16:53:53
【问题描述】:
我已经阅读并有点理解Use of lambda for cons/car/cdr definition in SICP。我的问题是理解它背后的原因。我的第一个问题是盯着看
(define (cons x y)
(lambda (m) (m x y)))
并且不理解这个函数实际上是如何进行任何形式的consing的。我从各种 Lisp/Scheme 书籍中了解到,Consing 是将内容放入列表中,即,
(cons 1 ()) => (1)
怎么样
(define (cons x y)
(lambda (m) (m x y)))
做任何事情比如consing?但随着我脑海中的光亮:cons 只是 car 和 cdr 最终定义的占位符。所以汽车是
(define (car z)
(z (lambda (p q) p)))
它预期传入的 z。但是这个z是什么?当我看到这个用法时:
(car (cons 1 2))
我终于明白了,是的,整个 cons 函数是 z,也就是说,我们将 cons 传递给 car!多么奇怪!
((lambda (m) (m 1 2)) (lambda (p q) p)) ; and then
((lambda (p q) p) 1 2)
这导致抓取第一个表达式,因为基本的汽车操作可以被认为是一个布尔值为真的 if 语句,因此,抓取第一个。
是的,所有列表都可以被认为是 cons-ed together 表达式,但是我们通过这个奇怪的向后定义赢得了什么?就好像任何最初的、独立的 cons 定义都没有密切关系。就好像 something 的使用定义了 something,就好像没有 something 直到它的使用限制它。这是闭包的主要用途吗?谁能给我一些其他的例子?
【问题讨论】:
-
我不认为我们能比Oscar's answer 做得更好。而且,您应该尝试 REPL 中的不同步骤来亲自查看。
-
我了解奥斯卡。我不明白为什么,我们为什么要这样做?这种闭包有什么用途?其他例子。等等等等
-
我也花了一段时间才明白这一点。我认为这个 cons/car/cdr 定义是用来说明数据结构和算法可以从任何特定的内部表示方式中抽象出来。另一个例子是,使用零和 succ 和 pred 函数的适当定义,您可以“构造”所有基本自然数数学(加法、减法、乘法、比较等),而无需使用语言固有的 +、-、* 运算符。它可能效率低下,但它从任何内部二进制表示中抽象出数字。
-
(1)和(1 . ())代表您在评估(cons 1 '())时得到的结果,但它不是存储在内存中的实际对象。就像20和40是十进制数32的正常表示,只是在不同的基础上。如果您要实现自己的 Scheme 实现,您将如何实现cons将决定如何实现car、cdr以及您需要如何实现read和display。