所以我知道在Scheme中定义的是动态作用域,并且允许静态作用域,但是下面的内容让我困惑:
如果我有
(let ((x 0))
(define f (lambda () x))
(display (f))
(let ((x 1))
(display (f))
)
)
它将显示00.到目前为止一切顺利。但是,如果我像这样为x添加额外的定义:
(let ((x 0))
(define f (lambda () x))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
它将显示undefined4。为什么是这样?为什么在评估f之后定义x 会影响(f)的返回值?为什么返回值“未定义”?
还值得一提的是,用letrec而不是define绑定f也会起作用:
(let ((x 0))
(letrec ((f (lambda () x)))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
)
返回00。
注意:我使用DrRacket并将语言设置为“Pretty Big”
答案 0 :(得分:4)
您在第二种情况下遇到的问题是(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
;; ...
)
它的行为更像是这样:
(let ([x 'undefined])
;; ... up here, `x` is 'undefined
(set! x 42)
;; ... down here, `x` is 42
)
答案 1 :(得分:1)
您的第二个和第三个代码段不是Scheme(R5RS,R6RS和R7RS都不是)。 <body>
(let
和其他)的<body> -> <definition>* <sequence>
<sequence> -> <command>* <expression>
<command> -> <expression>
定义为:
define
因此<definition>
(display
)无法关注<expression>
(> (let ((x 0))
(letrec ((f (lambda () x)))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
)
Unhandled exception
Condition components:
1. &who: define
2. &message: "a definition was found where an expression was expected"
3. &syntax:
form: (define x 4)
subform: #f
4. &trace: #<syntax (define x 4)>
>
)。您可能会得到令人困惑的结果,因为编译器/解释器错误地处理了'let'的扩展。
以下是'好'的R6RS编译器的作用:
{{1}}
答案 2 :(得分:0)
情况1:f的主体绑定到两个调用中的最外层let,导致00作为静态范围需要。
案例2:我对此并不十分肯定,但内部(define x 4)
会影响最外面的x = 0绑定,并且尽管在调用f之后是文本上的,但仍在整个范围内。然后,一些评估技巧的顺序使得第一次调用在新的x绑定完全初始化之前发生,因此它是“未初始化的”。内部的第二次调用在一切都被初始化之后发生,所以4。
案例3:现在我们已经明确地将letrec和define放在不同的范围中,f显然是指最外面的let。定义在这里什么都不做。