【问题标题】:The mechanism of anonymous function to call itself in Scheme?Scheme中匿名函数调用自身的机制?
【发布时间】:2013-11-01 21:39:04
【问题描述】:

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

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

(define eternity
    (lambda (x)
         (eternity x)))

代码是判断空列表,否则永远不会停止。

为什么“len”不是递归的?

【问题讨论】:

  • "len" 不是递归,因为它是 lambda 表达式的参数。它的价值可以是任何东西。这里是eternity。另请注意,第一个表达式不是定义。计算第一个表达式时,eternity 仍未定义。
  • 谢谢。我明白了。

标签: recursion scheme the-little-schemer anonymous-recursion


【解决方案1】:

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

((lambda (len) 
   (lambda (l)
     ...))
 eternity)

是一个应用程序,即一个函数调用。被调用的函数接受一个名为len 的参数,并返回另一个接受单个参数l 的函数。被调用的函数使用eternity 调用。当调用完成时,结果是这个函数:

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

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

(define eternity
  (lambda (x)
    (eternity x)))

也可以写成

(define (eternity x)
  (eternity x))

只需接受一个参数x,然后用x 调用eternity。那是一个无限循环。在上面,我写了“当返回时”,但实际上,(eternity (cdr l)) 从不 返回。所以,

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

是一个函数调用,它返回一个函数(lambda (l) …),如果调用一个空列表,则返回0,然后进入一个非空列表的无限循环。

从程序分析的角度来看,值得注意的是,还有其他值不会进入无限循环。例如,如果你用字符串调用它,那么(cdr l) 将是一个错误。

【讨论】:

    【解决方案2】:

    就像你说的,这是一个将长度函数定义为部分函数的定义,它只对空列表完成。但这还没有到 y-combinator 部分,它不是匿名函数调用自身的示例。

    l 是一个原子列表,它是计算(lambda (len) ...) 时返回的函数的参数。

    len 是一个作为参数传递给外部 lambda 的函数。

    外部表达式创建一个 lambda,并将 eternity 作为参数传入。外部 lambda 返回一个通过评估内部 lambda 创建的函数,返回的函数是以eternity 作为参数的东西。

    如果代码传递了一个空列表(意味着将整个第一部分包装起来,然后在另一组括号中加上 '()),那么它的计算结果当然会为 0。 len 永远不会被评估。

    如果代码传递了一个非空的纬度,那么它会尝试评估len 参数,你会得到一个无限递归。

    【讨论】:

      猜你喜欢
      • 2013-02-23
      • 2011-03-08
      • 1970-01-01
      • 2012-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      相关资源
      最近更新 更多