切换包时,词法绑定丢失了

时间:2015-08-21 03:36:48

标签: common-lisp packages swank

我想要的只是为swank加载一个初始化文件,这个文件在没有swank的情况下启动时不会影响我的lisp ......

我首先在我的文件中尝试了#+ swank(defun ...),这是从ccl-init加载的(在ccl 1.10 + windows上尝试这个),很快就意识到它是在swank加载之前来源的(显然)。

我的目标是在每次开始swank时定义一个简单的函数:cl-user。我刚刚用一个swank add-hook来加载我的init.lisp文件,因为我想在cl-user中定义函数,我在init.lisp中尝试了这个:

(let ((current-package *package*))
  (in-package :cl-user)
  (defun cd (dir)
    (swank:set-default-directory
      (parse-namestring dir)))
  (in-package current-package))

现在,我不记得是否允许在let中使用defun,但是lisp不会抱怨它,而是告诉我cur-pck符号不存在,而且当我们切换包时, cur-pck绑定超出范围。我认为cur-pck是一个词法绑定,它应该可以从词法区域内到达,独立于包,我错了吗?

为什么要换包?我想在某些初始化点从swank加载这个文件会定义一些swank包中的东西,这就是为什么我想先尝试切换到cl-user,定义函数符号,然后切换回让swank做它的事情。

此时我想我需要有人告诉我,我正在从错误的角度解决问题,我最好选择一个更简单的解决方案。

此外,出于上述情况的好奇心是完全错误的方法,有没有办法在函数或闭包中的另一个包中定义符号?

3 个答案:

答案 0 :(得分:8)

在表单中切换包对表单没有直接影响

让我们来看看:

(in-package "FOO")

(let ((x 10))
  (in-package "BAR")
  (setf x 20))

哪个x设置为20? FOO::XBAR::X

嗯,它是FOO::X。在执行期间切换包对已读取的符号没有影响。立即读取整个let表单,并使用*package*值。表单中有IN-PACKAGE本身对表单本身没有影响。

带有包前缀的符号

如果要在某个包中使用符号,只需编写包前缀:

cl-user:foo   ; if FOO is exported and the package exists

cl-user::foo  ; if foo is not exported and the package exists

例如:

(defun cl-user::cd (...) ...)

使用符号进行计算

您还可以在尚不知道的包中计算新符号:

(let ((sym-name "A-NEW-SYMBOL")
      (my-package-name "SOME-EXISTING-PACKAGE"))
  (intern sym-name my-package-name))

如果包不存在,您可以创建它。

您还可以设置计算符号的功能:

(setf (symbol-function (compute-a-function-symbol))
  #'(lambda ()
      'foo))

答案 1 :(得分:4)

如果要在不同的包中定义当前的函数,可以使用限定符号作为名称

(defun cl-user::cd (dir)
    (swank:set-default-directory
      (parse-namestring dir)))

绑定不会“丢失”。要进行测试,请自行在包装内添加(princ cur-pck)

如果您尝试评估(in-package *package*),您将看到代码无法切换包的原因。包内宏不评估其参数。将为我们提供我们想要评估的代码的代码是:

(let ((cur-pck *package*))
  (in-package :cl-user)
  (defun cd (dir)
    (swank:set-default-directory
     (1+ 2)))
  (princ cur-pck)
  `(in-package ,cur-pck)) 

然而,正如Rainer Joswig在回答中指出的那样,包装内容对已阅读的表格没有任何影响,因此即使作为一个宏,它也无法正常工作。

样式挑剔,不要使用缩写,写当前包。

答案 2 :(得分:2)

IN-PACKAGE是一个宏,而不是一个函数。您的代码中的问题是,(in-package cur-pck)尝试不切换到cur-pck变量表示的包,而是切换到名为CUR-PCK的包(显然不存在)。

您可以使用

临时设置包
(let ((*package* (find-package :cl-user)))
  (defun cd (dir)
    ...))

然而,再一次,实现你所做的最简单的方法是

(defun cl-user::cd (dir)
  ...)

完全消除了设置当前包的需要。