匿名函数在Scheme中调用自身的机制?

liu*_*liu 5 recursion scheme the-little-schemer anonymous-recursion

我正在阅读The Little Schemer并对以下代码感到困惑:

((lambda (len)
   (lambda (l)
      (cond
         ((null? l) 0)
         (else 
            (+ 1 (len (cdr l)))))))
   eternity)

(define eternity
    (lambda (x)
         (eternity x)))
Run Code Online (Sandbox Code Playgroud)

代码是确定空列表,否则它永远不会停止.

为什么" len"没有递归?

Jos*_*lor 5

尽管将文本替换应用于Lisp表单可能很危险(因为存在多重评估的危险等),在这种情况下,查看此表单并查看它如何组合起来可能会有所帮助:

((lambda (len) 
   (lambda (l)
     ...))
 eternity)
Run Code Online (Sandbox Code Playgroud)

是一个应用程序,即函数调用.被调用的函数接受一个被调用的参数,len并返回另一个带有单个参数的函数l.调用函数调用eternity.调用完成后,结果就是这个函数:

(lambda (l)
  (cond
    ((null? l) 0)
    (else (+ 1 (eternity (cdr l))))))
Run Code Online (Sandbox Code Playgroud)

现在,此函数获取一个列表l,如果它为空,则返回0.否则,它计算(cdr l)(列表的其余部分),并eternity使用该值进行调用.当返回时,1将添加到结果中,这是整个函数的返回值.当然,问题在于eternity

(define eternity
  (lambda (x)
    (eternity x)))
Run Code Online (Sandbox Code Playgroud)

也可以写成

(define (eternity x)
  (eternity x))
Run Code Online (Sandbox Code Playgroud)

只是需要一个参数x,然后调用eternity用x.这是一个无限循环.在上面,我写了"当它返回",但事实上,(eternity (cdr l)) 永远不会返回.所以,

((lambda (len)
   (lambda (l)
     (cond
       ((null? l) 0)
       (else (+ 1 (len (cdr l)))))))
 eternity)
Run Code Online (Sandbox Code Playgroud)

是一个函数调用,它返回一个函数(lambda (l) …),该函数0在使用空列表调用时返回,并进入带有非空列表的无限循环.

从事物的程序分析的一面,这是值得注意的是,有是针对这不会进入一个无限循环的其他值.例如,如果用字符串调用它,(cdr l)则会出错.