defpackage和in package调用中的变体



在Graham的书"ANSI Common Lisp"(1996)第137页中,举例说明在包中使用defpackage类似

(defpackage "MY-APPLICATION"
(:use "COMMON-LISP" "MY-UTILITIES")
(:nicknames "APP")
(:export "WIN" "LOSE" "DRAW"))
(in-package my-application)

defpackage调用使用字符串来传递包名称并列出导出的符号。虽然这种风格可以在旧代码中看到,但今天的主要用途似乎是

(defpackage :my-application
(:use :common-lisp :my-utilities)
(:nicknames :app)
(:export :win :lose :draw))
(in-package :my-application)

defpackagein-package调用中使用:my-application关键字所产生的规律性是一个微小但明显的差异。

我推测,第二种形式减少了内存中程序的大小,因为关键字都存储在关键字包中,而文字字符串代表它们自己,具有相同内容的文字字符串不需要共享它们的内存表示。(如果他们真的这样做了,那么改变其中一个字符串可能会产生奇怪的结果!)

这两种形式之间的实际区别是什么?为什么后者比前者更受欢迎?

除此之外,我偶尔会看到

;; Pay attention to the :export line
(defpackage :my-application
(:use :common-lisp :my-utilities)
(:nicknames :app)
(:export #:win #:lose #:draw))
(in-package :my-application)

#引入了一个读取器宏,但我不确定它对关键字有什么影响,也不确定它是如何修改defpackage声明的。

tl;dr

使用未理解的符号,如#:my-package

字符串指示符

公共lisp有一个字符串的概念代号(另请参阅代号)。

这意味着defpackage相当于他们的名字。

使用哪个代号

您有4个选项:

1实习符号

例如,

(defpackage my-package)

优势

Brevity

缺点

命名空间污染:符号my-package现在在水流中滞留*package*

2关键字

例如,

(defpackage :my-package)

优势

适度简洁(增加一个字符)

缺点

命名空间污染:符号:my-package现在在标准包装中实习关键字。

3字符串

例如,

(defpackage "MY-PACKAGE")

优势

没有命名空间污染。

缺点

  • 丑陋的upcase
  • 2个额外字符

4非故意符号

例如,

(defpackage #:my-package)

优势

没有命名空间污染。

缺点

2个额外字符

"丑陋的前缀"实际上是一个理想的功能,因为这是我使用未理解符号的唯一上下文,如果添加,emacs会很好地突出显示它们

(font-lock-add-keywords
'lisp-mode
'(("\(#:\)\(\(\s_\|\sw\)*\)"
(1 font-lock-comment-delimiter-face)
(2 font-lock-doc-face))))

到您的~/.emacs

您的示例:

(defpackage "MY-APPLICATION"
(:use "COMMON-LISP" "MY-UTILITIES")
(:nicknames "APP")
(:export "WIN" "LOSE" "DRAW"))
(in-package my-application)

然后通常会写:

(in-package "MY-APPLICATION")

如果您在defpackage中使用字符串,那么您也将在in-package中使用字符串。

使用字符串或未插入符号的主要优点之一是避免使用"不需要的"符号"污染"包装。

我推测,第二种形式减少了内存中程序的大小,因为关键字都存储在关键字包中,而文字字符串代表它们自己,内容相同的文字字符串不需要共享它们的内存表示。(如果他们真的这样做了,那么改变其中一个字符串可能会产生奇怪的结果!)

这是特定于实现的,取决于宏和底层数据结构的实现方式。例如,在LispWorks中,包对象:包名称是字符串,昵称是字符串,使用列表是包对象的列表,导出的符号存储为符号。因此,根据需要将来自CCD_ 11形式的数据转换成这些数据。

还要注意包的Common Lisp运算符将返回什么:package-name返回字符串,package-use-list返回包对象列表,do-external-symbols在符号上迭代。它们不使用关键字或未插入的符号。

最新更新