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

标签 dynamic lisp common-lisp scoping lexical

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

我目前正在学习 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 显然是未定义的?这恰好是我在第二个示例中所期望的...

任何见解将不胜感激...

最佳答案

使用 setf 设置 undefined variable 的效果在 ANSI Common Lisp 中是未定义的。

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

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

更新

  • 示例 1。

没什么可看的。

  • 示例 2

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

  • 示例 3

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

作为执行(执行?)其他操作的示例:默认情况下,CMUCL 实现还将示例 3 中的 x 声明为特殊的。设置一个 undefined variable 也会声明它是特殊的。

注意

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

记住:

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

基本相同

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

这意味着 let 绑定(bind)中的变量绑定(bind)和函数调用中的变量绑定(bind)以相同的方式工作。如果 x 早先在某个地方被声明为特殊的,那么两者都将涉及动态绑定(bind)。

这是在 Common Lisp 标准中指定的。例如参见对 SPECIAL declaration 的解释.

关于dynamic - Common Lisp 作用域(动态 vs 词法),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7787683/

相关文章:

lisp - 如何将 LISP 中的两个大整数相乘

javascript - jQuery动态表计算

javascript - 同步动态列表中的问题与来自服务器的请求列表(VueJs)

c# - 是否可以重载 C# 动态类型属性解析?

c - 从函数返回整数和数组

common-lisp - 通用 Lisp : how to access a row of a certain multi-dimension array?

方案:对象 () 不适用

lisp - 设置全局变量恢复到最后一个值

mysql - CentOS 上的 CLSQL 安装

lisp - 获取目录中的文件,逐行打印