是否将非功能重新分配为带有 set! 的功能?创建一个新框架?

Does re-assigning a non-function to be a function with set! create a new frame?

下面的代码让我很困惑:

(define (even-or-odd-letrec x)
  ((lambda (internal-even? internal-odd?)
     (set! internal-even? (lambda (n)
                (if (= n 0) 'even
                    (internal-odd? (- n 1)))))
     (set! internal-odd? (lambda (n)
               (if (= n 0) 'odd
                   (internal-even? (- n 1)))))
     (internal-even? x))
   #f #f))

我看的环境如下:

  1. even-or-odd-letrec 的环境中,internal-even?internal-odd? 最初绑定到 #f。他们的父环境是全局环境。
  2. set! 然后将这两个值更改为明显的 lambdas,但不会更改环境。
  3. 因为环境没有改变,所以对 internal-even? 的任何调用都将在全局环境中查找 internal-odd?,但一无所获。

那么这段代码是如何工作的?

回答您的问题标题:不,设置不会创建任何新框架。

Setting 设置当前环境框架中绑定的值。无论旧值和新值是什么。功能与否,没有区别。

同样,set! 不会更改值。它会更改 bindings' 值。绑定是名称及其值的配对。 Set!ting 更改该名称的绑定值。

被视为命名指针,在重新set! 之后,名称指向一个新值——该值作为第二个参数提供给set!

所以与你所说的相反,set! 确实 改变了 当前的环境框架——它改变了它对给定名称集的绑定。

  +---------------+                  +---------------+
  |  n1 ---> v1   |                  |  n1 ---> x    |
  |  n2 ---> v2   |   (set! n1 x)    |  n2 ---> v2   | 
  |---------------|  ------------->  |---------------| 
  |  ..code...    |                  |  ..code...    |
  |_______________|                  |_______________|

“任何对 internal-even? 的调用都会”......停止!这不是正确的看待方式。

lambda 创建的框架内对 internal-even? 的任何引用都将通过在同一框架中查找名称 internal-even? 下的值来解决,一切都会正常进行.

当你 (set! internal-even? (lambda (...) ... internal-odd? ...)) 时,确实 internal-odd? 仍然不是它应该的,但这没关系,因为它还没有查找值——因为 internal-even? 还不是 运行。当一个 lambda 表达式被求值时(这里,作为 set! 调用的一部分),它的值是这样的函数:时间到了,当这个函数 运行s,然后根据需要在其中查找任何名称的值.

当应用于两个参数值时,(lambda (internal-even? internal-odd?) ...) 会创建一个新环境,其中包含 internal-even?internal-odd? 的绑定。该环境中引用 internal-even?internal-odd? 的任何内容都将引用代码运行时这些绑定的当前值。 set! 通过改变绑定的值来改变这个环境,这样这些绑定的当前值现在是两个过程,它们本身引用这些绑定的当前值。


我认为,到目前为止,理解这一点的最简单方法是实现一个小解释器。做到这一点非常容易:您将 alists 用于环境,评估器几乎需要处理 iflambda 以及 set! 作为特殊情况。每个人都应该写一篇。

设置变量不会绑定新位置。但是请注意,绑定一个新变量并不意味着 create/enlarge 一个框架。如果您可以证明变量的行为,可以将变量保存在寄存器中而不是帧中(就像在 C 中一样),或者根本不保存它们。