为什么会发生这种行为此外,这是"实现定义的"差异,还是这些REPL中的一个错误?
请考虑这个公共Lisp代码
(defpackage :new)
(in-package new)
(+ 2 2)
在CMUCL中,这将计算为数字4。
在SBCL中,返回一个错误:
; in: + 2
; (NEW::+ 2 2)
;
; caught COMMON-LISP:STYLE-WARNING:
; undefined function: NEW::+
;
; compilation unit finished
; Undefined function:
; +
; caught 1 STYLE-WARNING condition
debugger invoked on a COMMON-LISP:UNDEFINED-FUNCTION in thread
#<THREAD "main thread" RUNNING {1000508083}>:
The function NEW::+ is undefined.
然而,当SBCL被评估为时,它将正确地调用"+">
(cl:+ 2 2)
CMUCL也与此合作。
当我查看HyperSpec时,我找不到一个明确的部分来处理这个上下文。我能找到的最接近的是:第11.1.2.2节COMMON-LISP-USER包。这让我相信SBCL有正确的解释;"NEW"没有从"COMMON-LISP"继承符号,因此整个COMMON LISP语言无法从"NEW(新("中访问但是真的很奇怪,三行字会毁掉整个语言,所以我还不清楚。
在CL标准中,当DEFPACKAGE中没有:use
子句时,哪个封装到使用是未定义的。
CLHS:DEFPACKAGE:
参数to:use设置按包名称命名的包将从中继承的包。如果未提供:use,则默认为与生成包的:use参数相同的实现相关值。
SBCL当时选择不使用任何包。
传统上,其他CL实现通常选择使用CL包和一些扩展包。当时的意图是,默认情况下,新包对Lisp编程(如包CL-USER
(非常有用。
对于可移植代码,您需要指定包应该使用哪些包。通常defpackage
和make-package
是要查看的运算符
您可以指定从中继承defpackage
和:use
中的符号的包,也可以将use-package
调用到同一端;我通常在defpackage
中做。我不知道CMUCL在这方面的表现与SBCL不同,但我总是在包中包含(:use :common-lisp)
。Common Lisp HyperSpecdefpackage
文档说:如果没有提供:use
,它默认为与make-package
的:use
参数相同的实现相关值。在这里你可以看到CMUCL和SBCL之间的区别:
CMUCL-
CL-USER> ;; CMUCL
; No value
CL-USER> (defpackage :new)
#<The NEW package, 0/9 internal, 0/2 external>
CL-USER> (package-use-list :new)
(#<The COMMON-LISP package, 0/6 internal, 978/1227 external>)
SBCL
CL-USER> ;; SBCL
; No value
CL-USER> (defpackage :new)
#<PACKAGE "NEW">
CL-USER> (package-use-list :new)
NIL
package-use-list
函数显示new
包在CMUCL中使用common-lisp
,但在SBCL中未使用。您可以通过显式use
ing包来避免此类问题:
CL-USER> (defpackage :new (:use :common-lisp))
#<PACKAGE "NEW">
CL-USER> (package-use-list :new)
(#<PACKAGE "COMMON-LISP">)
CL-USER> (in-package :new)
#<PACKAGE "NEW">
NEW> (+ 2 2)
4
在文件中,通常使用defpackage
表单中的:export
来导出符号,但从new
包中的REPL,您也可以定义函数并导出它们的符号以供其他包使用:
NEW> (defun add3 (x) (+ x 3))
ADD3
NEW> (export 'add3)
T
然后返回主工作区common-lisp-user
包,并调用use-package
访问新函数:
NEW> (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (use-package :new)
T
CL-USER> (add3 4)
7
这是对其他答案的补充。
我过去做过的一件事是写一个这样的宏:
(defvar *user-package-use-list*
(package-use-list (find-package ':common-lisp-user)))
(defmacro define-user-package (name &body options)
`(defpackage ,name
(:use ,@(mapcar #'package-name *user-package-use-list*))
,@options))
使用这个然后
(define-user-package :my-user-package)
将定义一个"类似"CL-USER
的包,因为它使用所有相同的包,并且它将以跨实现工作的方式来实现这一点。