我仍然不明白动态解释器与词汇解释器有何不同。
我正在研究方案,我发现很难知道像这样的简单代码如何动态地和词法地工作。
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
任何指导?
我仍然不明白动态解释器与词汇解释器有何不同。
我正在研究方案,我发现很难知道像这样的简单代码如何动态地和词法地工作。
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
任何指导?
词法绑定具有有限的可见性和无限的寿命。所有函数都“记住”它们创建的环境——这种函数称为词法闭包。
在您的示例中,这部分:
(let ((x 2018))
(lambda (y) (let ((result (cons x y)))
(set! x (+ x 1)) result))))
返回函数,它记住 x = 2018 的环境。该函数绑定到符号mystery
,当您调用它时,它会更改该环境中 x 的值。
> (mystery 1)
'(2018 . 1)
> (mystery 1)
'(2019 . 1)
在具有动态绑定(无限可见性、有限生命周期)的 Scheme 中,函数不记得创建它们的环境。因此,函数mystery
不会记住 x = 2018 的环境,并且(mystery 1)
在评估期间调用以错误结束(cons x y)
,因为符号x
没有价值。
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
这不是一个很好的例子来理解动态绑定和静态绑定之间的区别。这只是一个角落案例。
这个想法是,在静态绑定中,自由变量与静态范围(编写时可见的词法代码)相关联,而在动态绑定中,它们与动态代码(存储在执行堆栈上的内容)相关联。
您的代码计算result
结果为以下 lambda 表达式:
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))
在这个结果中,唯一的自由变量是X
。
将结果应用于 的值时 X 的值是Y
多少?
在静态作用域中,它将是 2018,在动态绑定中,X 的值将存储在堆栈中——例如,
(define X 100)
(define F (result 200)))
将应用result
绑定X=100
(X 将保留在堆栈中)。当然,X 的值并没有物理地保存在堆栈中,只是指向它所在的环境框架的指针,或者如果在环境上执行了重新生根,则可能保存在值单元中,等等。
要了解您的误解,您可以参加 lambda 演算课程。而且,当然,我在这里所说的假设您使用通用解释,许多其他解释可以与与您的输入示例相同的语法相关联,等等。
让我们用您的代码制作一个程序:
;; a global binding
(define x 100)
;; your function
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
;; just to add newlines in prints
(define displayln
(lambda (v)
(display v)
(newline)))
;; a indirect call
(define local-test
(lambda (x)
(displayln x)
(displayln (mystery 'local))
(displayln (mystery 'local))
(displayln x)))
(define global-test
(lambda ()
(displayln x)
(displayln (mystery 'global))
(displayln (mystery 'global))
(displayln x)))
;; program
(local-test 1)
(local-test 11)
(global-test 1)
(global-test 11)
正常 Scheme 的结果仅依赖于闭包,而不依赖于调用堆栈绑定变量:
1
(2018 local)
(2019 local)
1
11
(2020 local)
(2021 local)
11
1
(2022 global)
(2023 global)
1
11
(2024 global)
(2025 global)
11
动态“方案”的结果具有神秘的死代码。它什么也不做,因为绑定没有与函数对象一起保存。因此只有 activelet
和 calls 中的变量匹配:
1
(1 local)
(2 local)
3
11
(11 local)
(12 local)
13
100
(100 global)
(101 global)
102
102
(102 global)
(103 global)
104