如何解决函数定义中的自引用
在 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)
应该做两件事:
- 它应该在环境
M
中评估E
;让结果为x
。 - 它应该修改环境
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 举报,一经查实,本站将立刻删除。