编辑:我在第一个答案后更改了示例代码,因为我想出了一个简单的版本,它提出了相同的问题。
我目前正在学习Common Lisp的作用域属性。在我以为自己有了扎实的理解之后,我决定编写一些可以预测其结果的示例,但是显然我错了。我有三个问题,每个问题与下面的示例有关:
示例1:
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
输出:
5
*** - EVAL: variable X has no value
问题:这很有意义。 x是静态范围的,并且fun2在没有显式传递x的情况下无法找到x的值。
示例2:
(defvar x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
输出:
5
5
问题:我不明白为什么fun2突然看到x具有fun1给它的值,而不是100的值...
示例3:
(setf x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
输出:
5
100
问题:由于未声明的变量上调用setf显然是未定义的,因此我应该忽略这些结果吗?这恰好是我在第二个示例中所期望的...
任何见识将不胜感激...
使用setf
设置未定义变量的效果在ANSI Common Lisp中未定义。
defvar
将定义特殊变量。此声明是全局的,并且对let
绑定也有影响。这就是按照惯例将这些变量写为*foo*
的原因。如果您曾经用x
定义了defvar
,则将其声明为[[special,并且以后可以通过no声明它为[[lexical。
let
默认情况下提供局部词法变量。如果变量已经被声明为特殊变量(例如由于defvar
),那么它将仅创建一个新的本地动态绑定。更新
示例1。 没什么。
示例2
x
已被声明为特殊。现在,对变量x
的所有使用都使用动态绑定。调用函数时,将x
绑定到5
。动态地。现在,其他函数可以访问此动态绑定并获取该值。示例3
x
的符号值设置为100
。在fun1
中,x
受词法约束。在fun2
中,求值x
检索x
的符号值(或可能是动态绑定的值)。
x
声明为特殊。设置未定义的变量也将其声明为特殊。NOTE
在符合便携式标准的Common Lisp代码中,全局变量由defvar
和defparameter
定义。两者都声明这些变量是特殊的。现在,这些变量的所有使用都涉及动态绑定。
((lambda (x)
(sin x))
10)
基本上与]相同>
(let ((x 10)) (sin x))
这意味着
let
绑定中的变量绑定和函数调用中的变量绑定以相同的方式工作。如果x
早些时候被宣布为特殊,则两者都将涉及动态绑定。
这是在Common Lisp标准中指定的。例如,请参见SPECIAL declaration的说明。