动态与词法范围。
; One expects lexical scope.
(let (( a '(a)))
(defun func1 (x)
(setq a (cons x (cons (func2 x) a))))
(defun func2 (y)
(setq a (cons y a))))
(func1 'b)
=> (B (B A) B A)
在词汇上做到这一点,人们会期望以下。
- 用
(a)
代替func2
中的a
。 -
func2
用x
调用,即值b
。 -
func2
还附加了a
的值与(a)
。 - 所以
(cons y a)
的计算结果是(b a)
. -
(setq a (cons y a)))
(b a)
. - 所以
func1
缺点会(b a)
(a)
. - 然后
x
(b (b a) a))
. - 最终结果
(b (b a) a)
? 这是矛盾吗?
让我们尝试一个动态版本。 ;动态范围
(defparameter a '(a))
(defun func1 (x)
(setq a (cons x (cons (func2 x) a))))
(defun func2 (y)
(setq a (cons y a)))
(func1 'b)
=>(B (B A) B A)
这符合预期,但与词汇范围相同吗?
但以下内容根本不被接受。
; This won't work.
(let (( a '(a)))
(defun func1 (x)
(declare (special a))
(setq a (cons x (cons (func2 x) a))))
(defun func2 (y)
(declare (special a))
(setq a (cons y a))))
(func1 'b)
Error: Attempt to take the value of the unbound variable `A'.
这是怎么回事?
感谢您敏锐的眼睛。 这个例子来自一本 31 年前印刷的 Lisp 教科书,直接来自"动态与词汇范围"一章。 解释也直接出自那本书。 我猜没有检查词法范围,因为作者明确警告读者,词法范围不是在 Lisp 中完成的。 我很高兴这个问题解决了。我盯着它看了一会儿,不明白到底发生了什么。 这似乎是一个奇怪的矛盾。