问题描述
编辑:我改变了第一个答案后的示例代码,因为我想出了一个简单的版本,提出了相同的问题。
我正在学习Common Lisp的范围属性。在我以为我有一个坚实的理解之后,我决定编写一些我可以预测结果的例子,但显然我错了。我有三个问题,每个都有一个例子如下:
示例1:
code>(defmethod fun1(x)
(print x)
(fun2))
(defmethod fun2()
(print x))
(fun1 5)
输出:
5
*** - EVAL:变量X没有值
问题:这是有道理的。 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()
x))
(fun1 5)
输出:
5
100
问题:我应该忽略这些结果,因为在未声明变量上调用setf显然未定义?这恰好是我在第二个例子中所期待的...
任何见解将不胜感激...
使用SETF设置未定义变量的效果在ANSI Common Lisp中未定义。
DEFVAR将定义一个特殊的变量。此声明是全球性的,也对LET绑定有影响。这就是按照惯例,这些变量写成 * foo *
的原因。如果你已经用DEFVAR定义了X,那么它被声明为特殊的,没有办法在以后再声明它。
默认情况下,LET提供本地词法变量。如果变量已被声明为特殊的(例如因为DEFVAR),那么它只是创建一个新的本地动态绑定。
更新 / p>
- 示例1。
无法看到。
- 示例2
X
已被声明为特殊。变量X的所有使用现在都使用动态绑定。
调用该函数时,将X绑定到动态。其他功能现在可以访问此动态绑定并获取该值。
- 示例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标准中指定。请参阅的说明。
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...
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 on LET bindings. That's the reason that by convention these variables are written as *foo*
. If you have ever defined X with DEFVAR, 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 a DEFVAR), then it just creates a new local dynamic binding.
Update
- Example 1 .
Nothing to see.
- Example 2
X
has been declared special. All uses of the variable X now use dynamic binding.When calling the function, you bind X to 5. Dynamically. Other functions can now access this dynamic binding and get that value.
- Example 3
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 to 100. In FUN1, X is lexically bound. In FUN2 evaluating X retrieves the symbol value (or possibly to the dynamically bound value) of X.
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 and DEFPARAMETER. Both declare these variables to be special. ALL uses of these variables now involve dynamic binding.
Remember:
((lambda (x)
(sin x))
10)
is basically the same as
(let ((x 10))
(sin x))
Which means that variable bindings in LET bindings and variable bindings in function calls are working the same way. If X 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.
这篇关于常见的Lisp范围(动态vs词法)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!