use*_*086 5 scheme scoping racket
所以我知道在Scheme中定义的是动态作用域,并且允许静态作用域,但是下面的内容让我困惑:
如果我有
(let ((x 0))
(define f (lambda () x))
(display (f))
(let ((x 1))
(display (f))
)
)
Run Code Online (Sandbox Code Playgroud)
它将显示00.到目前为止一切顺利.但是,如果我为x添加额外的定义,如下所示:
(let ((x 0))
(define f (lambda () x))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
Run Code Online (Sandbox Code Playgroud)
它将显示undefined4.为什么是这样?为什么在评估f 之后定义x 会影响(f)的返回值?为什么返回值"未定义"?
还值得一提的是,用letrec而不是define绑定f也会起作用:
(let ((x 0))
(letrec ((f (lambda () x)))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
)
Run Code Online (Sandbox Code Playgroud)
返回00.
注意:我使用了DrRacket,上面写着"Pretty Big"
您在第二种情况下遇到的问题是为定义它的整个范围(define x 42)创建x了一个变量。现在,虽然变量是为整个范围定义的,但它的值在实际行之前是未定义的。(define x 42)
(let ()
;; up here, `x` is defined but has an undefined value
;; ...
(define x 42)
;; down here `x` has the value 42
;; ...
)
Run Code Online (Sandbox Code Playgroud)
它的表现更像这样:
(let ([x 'undefined])
;; ... up here, `x` is 'undefined
(set! x 42)
;; ... down here, `x` is 42
)
Run Code Online (Sandbox Code Playgroud)
情况 1:f 的主体在两次调用中都绑定到最外层的 let,导致静态作用域所需的 00。
情况 2:我对此不太确定,但内部(define x 4)阴影最外面的 x=0 绑定,并且在整个范围内,即使它在文本上是在调用 f 之后。然后,某种评估顺序使得第一次调用发生在新的 x 绑定完全初始化之前,因此它是“未初始化的”。内部 let 中的第二次调用发生在所有内容都初始化之后,所以 4。
情况3:现在我们已经明确地将letrec 和define 放在不同的作用域中,f 显然指的是最外面的let。该定义在这里不执行任何操作。