4

我想从我正在创建的包中定义一个名为“defun”的宏,并且我想将其导出以在某些地方使用。有一个名为 parenscript 的库,它在它的包中执行此操作,如下所示,

(export #:defun)

当我尝试在自己的包中执行此操作时,我收到此 SB​​CL 错误

Lock on package COMMON-LISP violated when defining DEFUN as a macro while in package COMMON-LISP-USER.

这是如何在 parenscript 库中完成的?我知道您可以输入表格;

(ps (defun function-name (args) (body)))

我希望能够做到这一点,但无法弄清楚这是如何做到的?

4

2 回答 2

4

您想遮蔽 CL 包中的原始符号。

CL-USER 1 > (defpackage "MY-PACKAGE" (:use "CL"))
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>

CL-USER 2 > (in-package "MY-PACKAGE")
#<The MY-PACKAGE package, 0/16 internal, 0/16 external>

MY-PACKAGE 3 > (shadow 'defun)
T

MY-PACKAGE 4 > (cl:defun defun () :my-defun-returns)
DEFUN

MY-PACKAGE 5 > (defun)
:MY-DEFUN-RETURNS

MY-PACKAGE 6 > (export 'defun)
T
于 2019-06-02T17:12:27.180 回答
3

您需要阅读有关包和符号的更多信息。在这里,我将在需要时对所有符号进行限定,这样我在谈论的是哪个符号就不会模棱两可了。

  1. 您不能重新定义CL:DEFUN,这会调用未定义的行为,并且您可能会通过使其无法使用来“破坏”您的运行时。这就是为什么 SBCL 有包的概念,这是一种避免错误修改包及其绑定的方法(您仍然可以解锁包,通常不需要)。

  2. 在您的宏范围内,您可以随意解释CL:DEFUN,这就是 Parenscript 通过将实际 Lisp 代码的子集翻译成 Javascript 所做的。

  3. 在任何其他包P中,您可以将其定义P:DEFUN为完全不同于CL:DEFUN. 您可以导出它,一切都很好,您可以同时使用两者P:DEFUN,并且CL:DEFUN随心所欲。

  4. 如果您想编写一个不合格的DEFUN符号并让读者找出引用了哪些符号,则可能会发生冲突。通常,库的用户可能会像这样定义一个包:

    (defpackage :foo (:use :cl :p))
    

    这会导致冲突,因为“CL”和“P”包都导出“DEFUN”。解决这个问题的一种方法是定义一个 Common Lisp 方言,该方言重新绑定DEFUN并重新导出“CL”中的所有其他符号。然后,您的用户必须只使用您的包而不是 CL 包。另一种方法是从 P 中使用CL 和仅影子导入“DEFUN”,因此这DEFUN是一个别名P:DEFUN(因此,您需要编写CL:DEFUN以显式引用 Common Lisp 宏)。

上面给出的链接更详细。

于 2019-06-02T17:22:00.993 回答