在包内覆盖 "defun"

Overriding "defun" within a package

我想在我正在创建的包中定义一个名为 "defun" 的宏,我想将其导出以在某些地方使用。有一个名为 parenscript 的库可以在它的包中执行此操作,

(export #:defun)

当我尝试在我自己的包中执行此操作时,出现此 SBCL 错误

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)))

我想做同样的事情,但不知道如何做?

您想隐藏 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

您需要阅读更多关于 packages and symbols 的内容。在这里,我将在需要时对所有符号进行限定,这样我所谈论的符号就不会出现歧义。

  1. 您不能重新定义 CL:DEFUN,这会调用未定义的行为,您可能会 "break" 您的运行时使其无法使用。这就是为什么 SBCL 对包有一个 locks 的概念,这是一种避免错误修改包及其绑定的方法(你仍然可以解锁包,因为你通常不需要到).

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

  3. 在任何其他包 P 中,您可以将 P:DEFUN 定义为与 CL:DEFUN 完全不同的 variable/function/macro/whatever。您可以导出它,一切都很好,您可以根据需要同时使用 P:DEFUNCL:DEFUN

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

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

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

上面给出的link有更多的细节。