其实有点棘手。
这是 Common Lisp 中未指定的内容之一。很遗憾。
LispWorks:
CL-USER 61 > (setf foo 1)
1
CL-USER 62 > (defun bar () foo)
BAR
CL-USER 63 > (bar)
1
CL-USER 64 > (let ((foo 2))
(bar))
1
let 中的最后一个 foo 使用词法绑定,因此不认为它是特殊的。
在(setf foo 1) 和(defun bar () foo) 的形式中,变量foo 被特定的Lisp 实现假定 是特殊的,它甚至可以被setf 声明为特殊的(- > 大多数实现都没有)。
以上let 形式返回1 还是2 在Common Lisp 语言标准中未指定。不过,大多数实现都会返回 1。
下一步:
CL-USER 65 > (let ((foo 2))
(declare (special foo))
(bar))
2
上面我们看到foo里面bar的使用其实是在let里面使用foo的动态绑定。
基本上未指定设置未定义变量的确切效果。可以假设变量是否特殊。大多数实现都喜欢NOT 声明它特殊,这样变量的进一步使用必须是特殊的。
但变量是否特殊,以及使用它的确切效果,实际上在 Common Lisp 语言标准中是未定义的。
大多数实现都同意
-
setf 设置一个未定义的变量只会改变符号的符号值
-
设置和检索变量是假设一个特殊变量
-
通过let(或类似方法)重新绑定变量不会创建特殊变量
-
编译器(如果使用)将警告未定义变量和/或假设特殊变量。
默认不同意的一个实现是 CMUCL -> setf 也将变量声明为特殊的,类似于 defparameter 所做的。
有关一般样式规则,请参阅ad absurdum 答案的最后一段。