Dynamic 通用Lisp范围(动态与词汇)

Dynamic 通用Lisp范围(动态与词汇),dynamic,lisp,common-lisp,scoping,lexical,Dynamic,Lisp,Common Lisp,Scoping,Lexical,编辑:我在第一个答案后更改了示例代码,因为我提出了一个简单的版本,它回避了相同的问题 我目前正在学习Common Lisp的作用域属性。在我认为自己有了坚实的理解之后,我决定编写一些我可以预测结果的例子,但显然我错了。我有三个问题,每个问题都与下面的一个例子有关: 例1: (defmethod fun1 (x) (print x) (fun2)) (defmethod fun2 () (print x)) (fun1 5) 输出: 5 *** - EVAL: variable

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

我目前正在学习Common Lisp的作用域属性。在我认为自己有了坚实的理解之后,我决定编写一些我可以预测结果的例子,但显然我错了。我有三个问题,每个问题都与下面的一个例子有关:

例1:

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

(defmethod fun2 ()
  (print x))

(fun1 5)
输出:

5 
*** - EVAL: variable X has no value
问:这是有道理的。x是静态作用域,如果不显式传递x,fun2无法找到x的值

例2:

(defvar x 100)

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

(defmethod fun2 ()
  (print x))

(fun1 5)
输出:

5
5
5
100
问:我不明白为什么x突然以fun1给出的值对fun2可见,而不是值为100

例3:

(setf x 100)

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

(defmethod fun2 ()
  (print x))

(fun1 5)
输出:

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


任何见解都将不胜感激……

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

defvar
将定义一个特殊变量。此声明是全局的,并且对
let
绑定也有影响。这就是为什么按照惯例,这些变量被写为
*foo*
。如果您曾经使用
defvar
定义过
x
,则它被声明为特殊的,并且以后没有方法声明它

默认情况下,让
提供本地词汇变量。如果变量已经声明为特殊变量(例如因为
defvar
),那么它只会创建一个新的本地动态绑定

更新

  • 例1
没什么可看的

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

  • 例3
这是Common Lisp中未定义的行为。您正在设置一个未声明的变量。然后发生的事情取决于实现。您的实现(大多数执行类似的操作)将
x
的符号值设置为
100
。在
fun1
中,
x
是词汇绑定的。在
fun2
中,计算
x
检索
x
的符号值(或可能是动态绑定值)

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

注意

在符合可移植标准的通用Lisp代码中,全局变量由
defvar
defparameter
定义。两者都声明这些变量是特殊的。这些变量的所有用途现在都涉及动态绑定

记住:

((lambda (x)
   (sin x))
 10)
基本上与

(let ((x 10))
  (sin x))
这意味着
let
绑定中的变量绑定和函数调用中的变量绑定的工作方式相同。如果
x
在前面的某个地方被声明为特殊的,那么这两种方法都会涉及动态绑定


这在通用Lisp标准中有规定。例如,请参阅对的解释。

我已经更新了我的原始帖子,添加了更精确的示例和问题,反映了我在理解上遇到的困难。具体来说,与第一个示例相比,我在第二个示例中演示的行为感谢您的澄清!我不认为我期望函数的参数值会像正常的自由变量一样受到影响。。。但我想每一次提及都是一样的。@antman8969:变量用法在任何地方都是一样的。有点令人惊讶的是,函数参数也可以动态绑定,并且它们受DEFVAR变量定义的影响。。。如果我很接近,请告诉我。。Exmaple 1:无需解释示例2:将x声明为动态变量会导致在运行时在动态变量堆栈上查找x的所有实例,这将导致fun2从fun1继承x的值,尽管它不是动态变量。例3:不知道……我想这是个很好的问题。乞求提问是不好的。使用DEFUN代替DEFUN。在这些示例中不需要DEFMETHOD。DEFUN创建了一个简单的函数。DEFMETHOD适用于一般函数,其中需要一些分派。