Common Lisp 中的动态和词法变量

2024-02-02

我正在读 Peter Seibel 的《Practical Common Lisp》一书。

在第 6 章“变量”部分中 “词法变量和闭包”和“动态,又名特殊变量”。http://www.gigamonkeys.com/book/variables.html http://www.gigamonkeys.com/book/variables.html

我的问题是,两个部分中的示例都显示了 (let ...) 如何隐藏全局变量,但并没有真正说明动态变量和词法变量之间的区别。

我理解闭包是如何工作的,但我真的不明白这个例子中的 let 有什么特别之处:

(defvar *x* 10)

(defun foo ()
  (format t "Before assignment~18tX: ~d~%" *x*)
  (setf *x* (+ 1 *x*))
  (format t "After assignment~18tX: ~d~%" *x*))


(defun bar ()
  (foo)
  (let ((*x* 20)) (foo))
  (foo))


CL-USER> (foo)
Before assignment X: 10
After assignment  X: 11
NIL


CL-USER> (bar)
Before assignment X: 11
After assignment  X: 12
Before assignment X: 20
After assignment  X: 21
Before assignment X: 12
After assignment  X: 13
NIL

我觉得这里没有什么特别的事情发生。外层foo in bar增加全局x, and foo被...围绕let in bar增加阴影x。有什么大不了的?我不明白这应该如何解释词汇变量和动态变量之间的区别。然而这本书继续这样说:

那么这是如何运作的呢?如何让 知道当它结合时x它是 应该创建动态绑定 而不是正常的词汇绑定? 它知道,因为这个名字已经被 宣布特殊。12 每个人的名字 用 DEFVAR 和定义的变量 DEFPARAMETER 自动声明 全球特殊。

如果会发生什么let会绑定x using “正常的词汇绑定”?总而言之,动态绑定和词法绑定之间有什么区别?这个示例对于动态绑定有何特殊之处?


这是怎么回事?

你说:感觉这里没有什么特别的事情发生。外层foo in bar增加全局x, and foo被...围绕let in bar增加阴影x。有什么大不了的?

The special这里发生的事情是这样的LET can影子的价值*x*。对于词法变量来说这是不可能的。

代码声明*x* to be special通过DEFVAR.

In FOO现在的价值*x*是动态查找的。FOO将采取当前动态绑定 of *x*或者,如果没有,则为符号的符号值*x*. A new 动态绑定例如,可以引入LET.

另一方面,词汇变量必须存在于词汇环境中的某个位置。LET, LAMBDA, DEFUN其他人可以引入这样的词汇变量。请参阅此处的词法变量x通过三种不同的方式介绍:

(let ((x 3))
  (* (sin x) (cos x)))

(lambda (x)
  (* (sin x) (cos x)))

(defun baz (x)
  (* (sin x) (cos x)))

如果我们的代码是:

(defvar x 0)

(let ((x 3))
  (* (sin x) (cos x)))

(lambda (x)
  (* (sin x) (cos x)))

(defun baz (x)
  (* (sin x) (cos x)))

Then X were special在上述所有三种情况下,由于DEFVAR声明,其中声明X to be special- 全球所有级别。正因为如此,才有了这样的约定:special变量为*X*。因此,只有周围有星星的变量才是special - by 习俗。这是一个有用的约定。

在你的代码中你有:

(defun bar ()
  (foo)
  (let ((*x* 20))
    (foo))
  (foo))

Since *x*已宣布special通过DEFVAR上面的代码中,LET构造引入了一个新的动态绑定 for *x*. FOO然后被调用。由于里面FOO the *x* uses 动态绑定,它查找当前的并发现*x*动态绑定到20.

的值special在当前动态绑定中找到变量。

当地特别声明

当地也有special声明:

(defun foo-s ()
  (declare (special *x*))
  (+ *x* 1))

如果变量已被声明special by a DEFVAR or DEFPARAMETER,那么本地的special声明可以省略。

词法变量直接引用变量绑定:

(defun foo-l (x)
  (+ x 1))

让我们在实践中看看:

(let ((f (let ((x 10))
           (lambda ()
             (setq x (+ x 1))))))
  (print (funcall f))    ; form 1
  (let ((x 20))          ; form 2
    (print (funcall f))))

这里所有的变量都是词法的。在form 2 the LET不会遮蔽X在我们的函数中f。不可以。该函数使用词法绑定变量,由LET ((X 10)。用另一个词法绑定来包围调用X in form 2对我们的功能没有影响。

咱们试试吧special变量:

(let ((f (let ((x 10))
           (declare (special x))
           (lambda ()
             (setq x (+ x 1))))))
  (print (funcall f))    ; form 1
  (let ((x 20))          ; form 2
    (declare (special x))
    (print (funcall f))))

现在怎么办?那样有用吗?

它不是!

The 第一种形式调用该函数并尝试查找动态值X但没有。我们得到一个错误form 1: X未绑定,因为没有有效的动态绑定。

Form 2会起作用,因为LETspecial声明引入了动态绑定X.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Common Lisp 中的动态和词法变量 的相关文章

  • 如何使用 Common Lisp 获得列表的所有可能排列?

    我正在尝试编写一个 Common Lisp 函数 该函数将给出列表的所有可能排列 每个元素仅使用一次 例如 列表 1 2 3 将给出输出 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 我已经写过一些有用的东西 但它
  • 阅读宏:你用它们做什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 LISP 中使用“ash”执行二分查找?

    所以 我现在正在阅读 Land of Lisp 事实证明 Lisp 与我见过的其他编程语言有很大不同 无论如何 本书提供了一些我们要输入到 CLISP REPL 中的代码 defparameter small 1 defparameter
  • 了解 LISP 中的绑定变量和自由变量

    我正在阅读SICP 又出现了绑定变量和自由变量的话题 然而 我对此感到困惑 术语 绑定变量 仅适用于形式参数变量吗 此外 文本还指出过程定义 绑定 其形式参数 这让我感到困惑 因为有些人说我们将值 绑定 到变量 显然 当我们谈论不同类型的变
  • Common Lisp 中的 LET 与 LET*

    我理解 LET 和 LET 并行绑定与顺序绑定 之间的区别 并且作为理论上的问题 它非常有意义 但有没有什么情况你曾经真正需要过 LET 在我最近查看的所有 Lisp 代码中 您可以将每个 LET 替换为 LET 而无需进行任何更改 编辑
  • 查找 lambda 表达式中的自由变量

    有谁知道如何找出 lambda 表达式中的自由变量 自由变量是不属于 lambda 参数的变量 我当前的方法 这对我毫无帮助 是简单地使用 car 和 cdr 来遍历表达式 我的主要问题是确定一个值是否是一个变量或者它是否是方案原语之一 有
  • Lisp 当前内存使用情况

    我需要从 Common Lisp 程序中找出当前使用了多少内存 我知道没有可移植的方法 标准函数room以文本形式将信息打印到标准输出 而不是将其作为值返回 但是sb kernel dynamic usage在 SBCL 工作 其他 Com
  • Common Lisp 中重置状态

    新手 Common Lisp 问题在这里 有没有办法重置环境状态 我的意思是 是否有一些命令可以使 REPL 恢复到启动后的相同状态 即取消所有变量 函数等 或者如果这不在 Common Lisp 标准中 是否有一些扩展在 SBCL 我使用
  • LISP 中的变量和符号有什么区别?

    从范围上来说 内存中的实际实现 语法 例如 if let a 1 a 是变量还是符号 约尔格的回答指出了正确的方向 让我补充一点 我将讨论与 Common Lisp 类似的 Lisp 作为数据结构的符号 符号是 Lisp 中真实的数据结构
  • let* 和 set 之间的区别?在 Common Lisp 中

    我正在从事一个基因编程爱好项目 我有一个函数 宏设置 当以 setq setf 形式评估时 将生成一个如下所示的列表 setq trees make trees 2 gt x abs x 然后它将绑定到 lambda 函数
  • 任意类型说明符上的 Defmethod?

    我想做的是 defgeneric fn x defmethod fn x integer 1 Positive integer defmethod fn x integer 1 Negative integer 我想要一个可以与任意类型说明
  • 为什么在基于 Lisp 的语言中习惯上将许多右括号放在一行上?

    通常代码如下所示 one thing another thing arg1 f arg5 r another thing arg1 f arg5 r 为什么不喜欢这样 one thing another thing arg1 f arg5
  • Lisp / Clojure:编写函数生成宏是个好主意吗?

    这个问题 https stackoverflow com q 7852351 346587要求创建一个 Clojure 宏来生成多个函数 我们找到了一种方法来做到这一点 但仍被 这是一个好主意吗 的问题所困扰 我的第一反应是并不真地 有两个
  • 在我的 Linux 机器上安装 lisp

    我使用 Vim 作为我的编辑器 Practical common Lisp 建议安装 Lispbox 我不知道如何使用 emacs 不知道如何用那个 T T 运行 lisp 代码 之后我找到了一个名为 limp vim 的 vim lisp
  • 修改功能;保存到 Lisp 中的新函数

    所以我认为 lisp 在其他语言中 的优点之一是它能够实现函数工厂 接受函数作为参数 返回新函数 我想使用此功能对函数进行小的更改并将其保存为新函数 这样如果对原始函数进行更改 它们也会反映在它所基于的新函数中 注意 我不是编写原始函数的人
  • Common Lisp——为什么这个符号不是外部的?

    我正在尝试在 ASDF 中运行测试 如下所示 foo asd defsystem foo tests depends on foo fiveam components module tests components file main pe
  • (cons 'a (cons 'b 'c)) 和 (cons 'a '(b.c)) 之间的 Lisp 区别

    有什么区别 cons a cons b c A B C and cons a b c A B C 我需要使用 cons 创建以下列表 a b c 所以我试图理解 是什么 代表 L E 我有以下内容 cons cons a b c 但它产生
  • 从 CCL 检索(加载)源代码?

    我打了电话 load code lisp 用CCL 然后不小心删除了code lisp 有什么办法可以找回源代码吗 CCL 在内存中是否有它 这是一个非常特殊的功能 这里只为克洛祖尔CL 该代码在其他地方不起作用 这在 CCL IDE 中对
  • 学习 Lisp 的资源 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 学习 LISP 的最佳方法是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐