为什么 Scheme 允许在闭包中对封闭环境进行变异?

day*_*day 3 scheme

以下方案代码

(let ((x 1))
   (define (f y) (+ x y))
   (set! x 2)
   (f 3) )
Run Code Online (Sandbox Code Playgroud)

其计算结果为 5 而不是 4。考虑到 Scheme 促进静态范围界定,这令人惊讶。允许后续突变影响闭包中封闭环境中的绑定似乎恢复到有点动态范围。允许的任何具体原因?

编辑:

我意识到上面的代码不太明显地揭示了我所关心的问题。我在下面放了另一个代码片段:

(define x 1)

(define (f y) (+ x y))

(set! x 2)

(f 3)  ; evaluates to 5 instead of 4
Run Code Online (Sandbox Code Playgroud)

Asu*_*awa 5

您在这里混淆了两个想法:作用域和通过内存间接。词法作用域保证您的引用x始终指向绑定x中的let绑定。

这在您的示例中没有违反。从概念上讲,let绑定实际上是在内存中创建一个新位置(包含1),该位置是绑定到 的值x。当该位置被取消引用时,程序会在该内存位置查找当前值。使用时set!,它会在内存中设置值。只有有权访问绑定到的位置x(通过词法范围)的各方才能访问或改变内存中的内容。

相比之下,动态范围允许任何代码更改您在 中引用的值f,无论您是否授予对绑定到的位置的访问权限x。例如,

(define f
  (let ([x 1])
    (define (f y) (+ x y))
    (set! x 2)
    f))

(let ([x 3]) (f 3))
Run Code Online (Sandbox Code Playgroud)

将返回6一个具有动态范围的虚构 Scheme。