这是在 Scheme 中利用一等函数的最奇怪的(也可能是更精彩的)示例之一。Little Schemer 中也有类似的东西,这是我第一次看到它的地方,我记得为它挠了好几天头。让我看看我是否可以用有意义的方式解释它,但如果不清楚,我很抱歉。
我假设您了解原语cons
,car
和 ,cdr
因为它们已经在 Scheme 中实现了,但只是为了提醒您:cons
构造一个对,car
选择该对的第一个组件并返回它,然后cdr
选择第二个组件并返回它。以下是使用这些函数的简单示例:
> (cons 1 2)
(1 . 2)
> (car (cons 1 2))
1
> (cdr (cons 1 2))
2
您粘贴的 , 和 的版本应该具有完全相同的cons
行为car
方式。cdr
我会试着告诉你怎么做。
首先,car
并cdr
没有定义在cons
. 在您的代码片段中,所有三个(cons
、car
和cdr
)都在顶层定义。该函数dispatch
是唯一在内部定义的函数cons
。
该函数cons
接受两个参数并返回一个参数的函数。重要的是这两个参数对内部函数是可见的dispatch
,这就是返回的内容。一会儿我会讲到的。
正如我在提醒中所说,cons
构造一对。这个版本cons
应该做同样的事情,但是它返回一个函数!没关系,我们并不真正关心这对是如何在内存中实现或布局的,只要我们能得到第一个和第二个组件。
因此,对于这个基于函数的新对,我们需要能够调用car
该对并将其作为参数传递,并获取第一个组件。在 的定义中car
,这个参数被称为z
。如果您要使用这些 new cons
、car
和cdr
函数执行我上面的相同 REPL 会话,则参数z
incar
将绑定到基于函数的对,这就是cons
返回的内容,即dispatch
. 这很令人困惑,但只要仔细考虑一下,你就会明白。
基于 的实现car
,它似乎采用一个参数的函数,并将其应用于数字0
。所以它适用dispatch
于0
,从 的定义中可以看出dispatch
,这就是我们想要的。内部与andcond
进行比较并返回or 。在这种情况下,它返回,这是 的第一个参数,也就是该对的第一个组件!所以选择第一个组件,就像在 Scheme 中正常的原语一样。m
0
1
x
y
x
cons
car
如果您对 遵循相同的逻辑cdr
,您会发现它的行为方式几乎相同,但将第二个参数返回给cons
, y
,这是该对的第二个组成部分。
有几件事可以帮助您更好地理解这一点。一种是回到第 1 章中对求值替换模型的描述。如果你仔细而细致地遵循这个替换模型,用一些非常简单的例子来使用这些函数,你会发现它们是有效的。
另一种不那么乏味的方法是尝试dispatch
直接在 REPL 中使用该功能。下面,变量p
被定义为引用dispatch
返回的函数cons
。
> (define p (cons 1 2))
#<function> ;; what the REPL prints here will be implementation specific
> (p 0)
1
> (p 1)
2