Common Lisp 作用域(动态与词法)
编辑:我在第一个答案后更改了示例代码,因为我想出了一个简单的版本,它提出了相同的问题。
我目前正在学习 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 就无法找到它。
示例 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 显然是未定义的?这恰好是我在第二个例子中所期望的......
任何见解将不胜感激......
EDIT: I changed the example code after the first answer because I came up with a simple version that begs the same questions.
I am currently learning Common Lisp's scoping properties. After I thought I had a solid understanding I decided to code up some examples that I could predict the outcome of, but apparently I was wrong. I have three question, each one relating to an example below:
Example 1:
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
*** - EVAL: variable X has no value
Question: This makes sense. x is statically scoped and fun2 has no way of finding the value of x without having it passed explicitly.
Example 2:
(defvar x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
5
Question: I don't understand why x is suddenly visible to fun2 with the value that fun1 gave it, instead of having a value of 100...
Example 3:
(setf x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
100
Question: Should I ignore these results since calling setf on an undeclared variable is apparently undefined? This happens to be what I would expect in my second example...
Any insight would be greatly appreciated...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用
setf
设置未定义变量的效果在 ANSI Common Lisp 中未定义。defvar
将定义一个特殊变量。该声明是全局的,并且对let
绑定也有影响。这就是按照惯例这些变量被写为*foo*
的原因。如果您曾经使用defvar
定义过x
,则它被声明为特殊,并且没有方式可以声明它< em>词汇稍后。let
默认情况下提供局部词法变量。如果该变量已被声明为特殊变量(例如由于defvar
),那么它只会创建一个新的本地动态绑定。更新
没什么可看的。
x
已被声明为特殊。现在,变量x
的所有使用都使用动态绑定。调用该函数时,将
x
绑定到5
。动态地。其他函数现在可以访问此动态绑定并获取该值。这是 Common Lisp 中的未定义行为。您正在设置一个未声明的变量。接下来会发生什么取决于实现。您的实现(大多数执行类似的操作)将
x
的符号值设置为100
。在fun1
中,x
是词法绑定的。在fun2
中,计算x
会检索x
的符号值(或者可能是动态绑定值)。作为做了(做?)其他事情的实现的示例:默认情况下,CMUCL 实现也会将示例 3 中的
x
声明为特殊。设置未定义的变量也声明它是特殊的。注意
在符合可移植标准的 Common Lisp 代码中,全局变量是用
defvar
和defparameter
定义的。两者都声明这些变量是特殊的。现在这些变量的所有使用都涉及动态绑定。请记住:
与 基本相同
这意味着
let
绑定中的变量绑定和函数调用中的变量绑定的工作方式相同。如果x
早先在某个地方被声明为特殊,则两者都将涉及动态绑定。这是 Common Lisp 标准中指定的。例如,请参阅特殊声明的说明。
The effects of setting an undefined variable using
setf
is undefined in ANSI Common Lisp.defvar
will define a special variable. This declaration is global and also has effect onlet
bindings. That's the reason that by convention these variables are written as*foo*
. If you have ever definedx
withdefvar
, it is declared special and there is no way to declare it lexical later.let
by default provides local lexical variables. If the variable was already declared special (for example because of adefvar
), then it just creates a new local dynamic binding.Update
Nothing to see.
x
has been declared special. All uses of the variablex
now use dynamic binding.When calling the function, you bind
x
to5
. Dynamically. Other functions can now access this dynamic binding and get that value.This is undefined behavior in Common Lisp. You are setting an undeclared variable. What happens then is implementation dependent. Your implementation (most do something similar) sets the symbol value of
x
to100
. Infun1
,x
is lexically bound. Infun2
evaluatingx
retrieves the symbol value (or possibly to the dynamically bound value) ofx
.As an example for an implementation that did (does?) something else: the CMUCL implementation would also have declare
x
in example 3 by default to be special. Setting an undefined variable also declares it special.NOTE
In portable standard compliant Common Lisp code the global variables are defined with
defvar
anddefparameter
. Both declare these variables to be special. ALL uses of these variables now involve dynamic binding.Remember:
is basically the same as
Which means that variable bindings in
let
bindings and variable bindings in function calls are working the same way. Ifx
would have been declared special in some place earlier, both would involve dynamic binding.This is specified in the Common Lisp standard. See for example the explanation to the SPECIAL declaration.