1

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

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

我的目标是每次开始 swank 时在 :cl-user 中定义一个简单的函数。我刚刚用一个时髦的 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 做这件事。

在这一点上,我想我需要有人告诉我我从错误的角度处理问题,我应该更好地选择一个更简单的解决方案。

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

4

3 回答 3

8

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

让我们看看这个:

(in-package "FOO")

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

x它设置为20 ?FOO::X还是BAR::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))
于 2015-08-21T07:23:12.907 回答
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 在他的回答中指出的那样,in-package 对已经读取的表单没有影响,因此即使作为宏它也无法按预期工作。

A style nitpick,不要使用缩写,写 current-package。

于 2015-08-21T04:09:58.963 回答
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)
  ...)

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

于 2015-08-21T04:02:55.867 回答