为什么会发生这种行为?另外,这是一个 "实现定义 "的差异,还是这些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 "中访问。但是 真的很奇怪,三条线会杀死整个语言,所以我还是不清楚。
你可以指定包,从包中继承符号,在 defpackage
与 :use
,或者你可以打电话 use-package
以达到同样的目的;我通常会在 defpackage
. 我不知道CMUCL在这方面的表现与SBCL不同,但我总是将 (:use :common-lisp)
在我的软件包中。常见的Lisp HyperSpec defpackage
文件说。如果 :use
不提供,它的默认值与实现中的 :use
争论 make-package
. 在这里你可以看到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
包使用的是 common-lisp
中,但在 SBCL 中则不然。你可以通过在CMUCL中显式的 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
在一个文件中,通常会使用 :export
在 defpackage
形式导出符号,但从 REPL 中的 new
包,您也可以定义函数并导出它们的符号,以便在其他包中使用。
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
在CL标准中并没有定义哪种包来访问 使用 当没有 :use
DEFPACKAGE中的子句。
CLHS: DEFPACKAGE:
:use的参数设置了由package-name命名的包将继承的包。如果没有提供 :use,则默认为相同的包。依赖于实施的价值 作为make-package的:use参数。
SBCL选择不使用 使用 那么任何包。
传统上其他的CL实现通常会选择 使用 CL包加上一些扩展包。当时的意图是,一个新的包默认为 有用的 用于Lisp编程,如软件包 CL-USER
.
对于可移植的代码,你需要指定一个包应该有哪些包。使用. 通常情况下 defpackage
和 make-package
是要看的运算符。
这是对其他答案的补充。
我过去做过的一件事是写一个这样的宏。
(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
在某种意义上说,它使用所有相同的包,并且它将以一种跨实现的方式来实现这一点。