LISP中的REVERSE功能

时间:2013-12-17 10:49:38

标签: functional-programming lisp

任何人都可以详细解释以下纯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绑定到NILIN绑定到列表L。 现在,如果第一个参数(IN)为空(NULL?),我们就完成了,我们可以返回OUT,这是列表,已成功反转。 否则,我们必须以REV作为第一个参数递归调用OUT+the first element of IN,并以rest of IN作为第二个参数。这是怎么回事?

唯一的问题是:LAMBDA这里有什么关系?

1 个答案:

答案 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来实现,重置每个迭代的形式参数,从而服务作为循环变量)。