Common Lisp范围(动态与词汇)

时间:2011-10-16 22:08:01

标签: dynamic lisp common-lisp scoping lexical

编辑:我在第一个答案之后更改了示例代码,因为我提出了一个简单的版本,提出了同样的问题。

我目前正在学习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的值。

示例2:

(defvar x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

输出:

5
5

问题:我不明白为什么x对fun2突然可见,其中fun1给出了值,而不是值为100 ...

示例3:

(setf x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

输出:

5
100

问题:我是否应该忽略这些结果,因为在未声明的变量上调用setf显然是未定义的?这恰好是我在第二个例子中所期望的......

非常感谢任何见解......

1 个答案:

答案 0 :(得分:18)

使用SETF设置未定义变量的效果在ANSI Common Lisp中未定义。

DEFVAR将定义一个特殊变量。此声明是全局的,也会对LET绑定产生影响。这就是按照惯例,这些变量写成*foo*的原因。如果您曾经使用DEFVAR定义了X,那么它被声明为特殊的,并且以后无法将其声明为词汇。

默认情况下,LET提供本地词法变量。如果变量已经被声明为特殊(例如由于DEFVAR),那么它只是创建一个新的本地动态绑定。

<强>更新

  • 实施例1。

没什么可看的。

  • 示例2

X已被宣布为特别。变量X的所有用法现在都使用动态绑定。 调用该函数时,将X绑定到5.动态。其他函数现在可以访问此动态绑定并获取该值。

  • 示例3

这是Common Lisp中未定义的行为。您正在设置未声明的变量。然后发生的是依赖于实现的。您的实现(大多数做类似的事情)将X的符号值设置为100.在FUN1中,X是词法绑定的。在FUN2中,评估X检索X的符号值(或可能是动态绑定值)。

作为一个实现的例子,做了(做?)其他事情:CMUCL实现也默认在示例3中声明X是特殊的。设置一个未定义的变量也声明它是特殊的。

注意

在便携式标准兼容Common Lisp代码中,全局变量使用DEFVAR和DEFPARAMETER定义。两者都声明这些变量是特殊的。现在,这些变量的所有使用都涉及动态绑定。

记住:

((lambda (x)
   (sin x))
 10)

基本相同
(let ((x 10))
  (sin x))

这意味着LET绑定中的变量绑定和函数调用中的变量绑定的工作方式相同。如果X先前在某个地方被宣布为特殊,则两者都涉及动态绑定。

这在Common Lisp标准中指定。例如,请参阅SPECIAL declaration的解释。