微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

函数定义中的自引用

如何解决函数定义中的自引用

在 Y-combinator (https://mvanier.livejournal.com/2897.html) 的解释中,

  (define almost-factorial
    (lambda (f)
      (lambda (n)
        (if (= n 0)
            1
            (* n (f (- n 1)))))))


  (define factorialA (almost-factorial factorialA))

它说在标准方案中,factorialA 的定义将进入无限循环,但是实现它会出现错误,说 factorial A 未定义。

我认为这是预期的,因为当我们定义时(如果不是使用 lambda),我们正在评估最终将计算参数的定义,其中一个是尚未定义的相同函数

这是否正确,那么我们如何解释上述文章? 谢谢

解决方法

考虑表达式 (define p M),其中 M 是某个表达式,而 p 是一个变量。

假设我们在环境 E 中评估这个表达式。评估 (define p M) 应该做两件事:

  1. 它应该在环境 M 中评估 E;让结果为 x
  2. 它应该修改环境 E,以便 p 绑定到 x

那么,当我们在 (define factorialA (almost-factorial factorialA)) 尚未定义的环境 E 中评估 factorialA 时会发生什么?

首先,我们尝试在环境 (almost-factorial factorialA) 中评估 E。为此,我们首先评估 almost-factorial,它成功。然后我们评估 factorialA,它失败了,因为 factorialA 没有在环境 E 中定义。因此,整个事情应该会失败。

另一方面,如果我们尝试

(define (returns-factorialA) (almost-factorial (returns-factorialA)))
(define factorialA (returns-factorialA))

这确实陷入了无限循环。这大概就是这篇文章的作者要找的。​​p>

,

从 SICP 的角度来看,这不是一个自引用过程,因为 factorialA 是一个值,而不是过程。

在第 4 章 Representing Expressions 中,我们开发了一个方案评估器:

(define (definition-value exp)
  (if (symbol? (cadr exp))
      (caddr exp)
      (make-lambda (cdadr exp)   ; formal parameters
                   (cddr exp)))) ; body

这意味着如果 define 之后的表达式是像 factorialA 这样的原始符号,那么它将立即评估表达式的主体并将其值赋给 factorialA。但是如果它是一个像 (factorialA)(factorialA n) 这样的列表,那么它将创建一个 lambda 表达式。对 lambda 表达式求值时,会创建一个过程,这意味着仅在调用该过程时才对主体进行求值。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。