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

发布于 2024-12-10 09:28:28 字数 920 浏览 1 评论 0原文

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

我目前正在学习 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

2024-12-17 09:28:28

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

defvar 将定义一个特殊变量。该声明是全局的,并且对 let 绑定也有影响。这就是按照惯例这些变量被写为 *foo* 的原因。如果您曾经使用 defvar 定义过 x,则它被声明为特殊,并且没有方式可以声明它< em>词汇稍后。

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

更新

  • 示例 1 。

没什么可看的。

  • 示例 2

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

  • 示例 3

这是 Common Lisp 中的未定义行为。您正在设置一个未声明的变量。接下来会发生什么取决于实现。您的实现(大多数执行类似的操作)将 x符号值设置为100。在 fun1 中,x 是词法绑定的。在 fun2 中,计算 x 会检索 x 的符号值(或者可能是动态绑定值)。

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

注意

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

请记住:

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

与 基本相同

(let ((x 10))
  (sin x))

这意味着 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 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文