动态绑定变量:恢复为先前状态

时间:2018-05-05 15:22:17

标签: common-lisp

我试图了解变量的动态和词汇绑定。 当我在这个问题上遇到问题时,我正在浏览SO和一些链接: https://www.emacswiki.org/emacs/DynamicBindingVsLexicalBinding#toc2

我运行了这段代码:

(let ((a 1))
  (let ((f (lambda () (print a))))
    (let ((a 2))
      (funcall f))))

预期结果:1(以及警告说第二个a变量未使用,这是正常的)。

接下来,我试过了:

(defvar a 99)

重新编写第一个代码。结果是2,就像教程说的那样。然后,为了进一步实验,我尝试删除动态绑定变量a,再次获取1

我尝试(makunbound 'a)甚至(setq a 55)(我默认尝试过这个,我认为如果我理解正确的话,全局词汇绑定依赖于实现......)。 makunbound似乎删除了符号,但是"动态绑定状态"无论如何似乎都得救了。结果仍为2

如何将Common Lisp重置为先前的状态(在动态绑定a变量之前)?重启SLIME可以做到这一点,但我宁愿有办法以编程方式做到这一点......

感谢您的回答。

1 个答案:

答案 0 :(得分:2)

没有便携式方式来还原 special proclaim通货膨胀。 (CLISP提供 notspecial)。

但是,您可以使用unintern 在某种程度上:它会使 new 代码将您的符号视为不符合 special因为它现在是不同的符号:

(defun test-a ()
  (let ((a 1))
    (let ((f (lambda () (print a))))
      (let ((a 2))
        (funcall f)))))
(test-a)
==> 1
(defvar a)
(test-a)
==> 2

现在,让我们试着"还原" defvar

(unintern 'a)
(test-a)
==> 2

糟糕!让我们看看:

(fdefinition 'test-a)
#<FUNCTION TEST-A NIL (DECLARE (SYSTEM::IN-DEFUN TEST-A))
  (BLOCK TEST-A
   (LET ((#:A 1)) (LET ((F (LAMBDA NIL (PRINT #:A)))) (LET ((#:A 2)) (FUNCALL F)))))>

你知道,test-a仍在使用现在未处理的旧符号a(因此打印为#:A)。要返回,您需要重新eval上面的defun,然后才能获得

(test-a)
==> 1

再次!