任何人都可以详细解释以下纯LISP功能的工作原理:
(DEFINE (REVERSE (LAMBDA (L)
(REV NIL L))))
(DEFINE (REV (LAMBDA (OUT IN)
(COND ((NULL IN) OUT)
(T (REV (CONS (CAR IN) OUT) (CDR IN))))))
该函数应该颠倒列表中元素的顺序,这很清楚,但我仍然无法理解它是如何工作的。
* 编辑 *
好吧,我相信我明白了。
使用列表作为参数调用REVERSE
函数,并使用REV
调用NIL
函数,并将L
列为参数。
REV :OUT
绑定到NIL
,IN
绑定到列表L
。
现在,如果第一个参数(IN
)为空(NULL
?),我们就完成了,我们可以返回OUT
,这是列表,已成功反转。
否则,我们必须以REV
作为第一个参数递归调用OUT+the first element of IN
,并以rest of IN
作为第二个参数。这是怎么回事?
唯一的问题是:LAMBDA
这里有什么关系?
答案 0 :(得分:3)
是的,它是如何运作的。这被称为用于编写tail recursive函数的累加器参数技术。它有助于通过一些例子可视化其操作,例如
reverse [1,2,3,4]
= rev NIL [1,2,3,4]
= rev [1] [2,3,4]
= rev [2,1] [3,4]
= rev [3,2,1] [4]
= rev [4,3,2,1] NIL
= [4,3,2,1]
似乎你的代码来自一个古老的(第一版,1982,ISBN 0-471-08755-6)textbook。在今天的方案中,例如它的写法几乎相同,但没有额外的括号(重新定义了很少的常量):
(define reverse (lambda (l) .... ))
(define rev (lambda (out in) .... ))
(define NIL '())
(define T #t)
(define NULL null?)
所谓的“lambda表单”,即以lambda
“keyword”开头的表单(格式良好,带括号的代码片段),表示匿名函数。符号lambda
后面的列表指定了此类函数的形式参数。 define
允许我们命名由lambda表单创建的函数。这样我们可以使用它的名称在其定义中对它进行递归调用。
这个递归调用在tail position中,所以这个函数的操作相当于一个循环(通过重用函数调用的stack frame来实现,重置每个迭代的形式参数,从而服务作为循环变量)。