【问题标题】:Self-reference in function definition函数定义中的自引用
【发布时间】:2021-06-06 18:45:31
【问题描述】:

在这个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))

它表示阶乘 A 的定义将进入标准方案中的无限循环,但是执行它会给出一个错误,说阶乘 A 未定义。

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

这是正确的,那么我们该如何解释上面的文章呢? 谢谢

【问题讨论】:

    标签: scope scheme lisp sicp y-combinator


    【解决方案1】:

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

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

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

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

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

    另一方面,如果我们尝试

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

    这确实会陷入无限循环。这可能是本文作者所寻找的。​​p>

    【讨论】:

    • 我认为almost-factorial不能单独“评估”,因为它是一个以factorialA为参数的函数,只是因为在定义中遇到factorialA,我们找不到它它还没有定义。
    • @user10206517 你把评估和申请混为一谈了。要评估(f x) 形式的表达式,我们首先评估f,然后评估x,最后将f 应用于x。函数也必须被评估——我们可能会遇到((if (= a b) (lambda (x) (+ 1 x)) (lambda (x) (+ 2 x))) 2)这样的情况。
    • 对不起,第二件事是如何工作的,它也指的是未定义的 (returns-factorialA)。还有为什么在第一种情况下定义的内容周围有额外的括号?
    • 第二个定义等价于(define returns-factorialA (lambda () (almost-factorial (returns-factorialA))))。我们将returns-factorialA 定义为应该返回factorialA 的0 输入函数。在第二种情况下,当我们尝试调用returns-factorialA 时,我们进入了一个无限循环。
    【解决方案2】:

    从 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 表达式时,会创建一个过程,这意味着只有在调用该过程时才会计算主体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 1970-01-01
      • 2018-08-24
      • 2013-04-05
      • 2018-02-22
      相关资源
      最近更新 更多