Common Lisp作用域(动态 vs 词法)

14

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

我目前正在学习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:不需要解释示例2:将x声明为动态变量会导致在运行时在动态变量堆栈上查找所有x的实例,这将导致fun2从fun1继承x的值,尽管它不是动态变量。示例3:没有头绪...我猜它是未定义的。 - Anthony Naddeo
提出问题是好的。乞求问题是不好的。 - luser droog
不要使用DEFMETHOD,而是使用DEFUN。在这些示例中不需要DEFMETHOD。DEFUN创建一个简单的函数。DEFMETHOD用于通用函数,其中需要一些分派。 - Rainer Joswig
1个回答

24
使用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实现还默认声明x为特殊变量。设置未定义变量也会将其声明为特殊变量。 注意 在可移植的标准兼容的Common Lisp代码中,全局变量使用defvardefparameter定义。这两者都声明这些变量为特殊变量。所有对这些变量的使用都涉及动态绑定。
记住:
((lambda (x)
   (sin x))
 10)

基本上和

(let ((x 10))
  (sin x))
这意味着在 let 绑定和函数调用中的变量绑定方式是相同的。如果 x 在之前的某个地方被声明为特殊变量,那么两者都将涉及动态绑定。
这在 Common Lisp 标准中有说明。例如,请参阅 SPECIAL 声明的解释

我已经更新了原始帖子,并提供了更精确的示例和问题,以反映我曾经遇到的困难。具体来说,我第二个示例中展示的行为与我的第一个示例相比有何不同。 - Anthony Naddeo
谢谢澄清!我没有想到函数参数值会像普通自由变量一样受到影响...但我想每个提及都是一样处理的。 - Anthony Naddeo
1
@antman8969:变量的使用在任何地方都是相同的。有点令人惊讶的是,函数参数也可以动态绑定,并且它们受DEFVAR定义的变量的影响。 - Rainer Joswig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接