Common Lisp 实现之间不同的“:cl”包处理
different ":cl" package handling between Common Lisp implementations
为什么会发生这种行为?
此外,这是 "implementation defined" 差异,还是其中一个 REPL 错误?
请考虑这个 Common Lisp 代码...
(defpackage :new)
(in-package new)
(+ 2 2)
在 CMUCL 中,这计算为数字四。
在 SBCL 中,这个 returns returns 一个错误:
; 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 时,我无法找到解决此上下文的明确部分。我能找到的最接近的是:Section 11.1.2.2 The COMMON-LISP-USER Package。这让我相信 SBCL 的解释是正确的; "NEW" 没有从 "COMMON-LISP" 继承符号,因此无法从 "NEW" 访问整个 Common Lisp 语言。 但是三行就把整个语言都干掉了,所以我还是不清楚。
您可以使用:use
指定从defpackage
中继承符号的包,或者您可以调用use-package
达到相同的目的;我通常在 defpackage
内完成。我不知道 CMUCL 在这方面的表现与 SBCL 不同,但我总是在我的包中包含 (:use :common-lisp)
。 Common Lisp HyperSpec defpackage
文档说:If :use
is not supplied, it defaults to the same implementation-dependent value as the :use
argument to 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
包在 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
当 DEFPACKAGE 中没有 :use
子句时,使用 打包的 CL 标准未定义。
CLHS:DEFPACKAGE:
The arguments to :use set the packages that the package named by package-name will inherit from. If :use is not supplied, it defaults to the same implementation-dependent value as the :use argument to make-package.
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)
将定义一个 'like' CL-USER
的包,因为它使用所有相同的包,并且它将以跨实现工作的方式执行此操作。
为什么会发生这种行为? 此外,这是 "implementation defined" 差异,还是其中一个 REPL 错误?
请考虑这个 Common Lisp 代码...
(defpackage :new)
(in-package new)
(+ 2 2)
在 CMUCL 中,这计算为数字四。
在 SBCL 中,这个 returns returns 一个错误:
; 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 时,我无法找到解决此上下文的明确部分。我能找到的最接近的是:Section 11.1.2.2 The COMMON-LISP-USER Package。这让我相信 SBCL 的解释是正确的; "NEW" 没有从 "COMMON-LISP" 继承符号,因此无法从 "NEW" 访问整个 Common Lisp 语言。 但是三行就把整个语言都干掉了,所以我还是不清楚。
您可以使用:use
指定从defpackage
中继承符号的包,或者您可以调用use-package
达到相同的目的;我通常在 defpackage
内完成。我不知道 CMUCL 在这方面的表现与 SBCL 不同,但我总是在我的包中包含 (:use :common-lisp)
。 Common Lisp HyperSpec defpackage
文档说:If :use
is not supplied, it defaults to the same implementation-dependent value as the :use
argument to 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
包在 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
当 DEFPACKAGE 中没有 :use
子句时,使用 打包的 CL 标准未定义。
CLHS:DEFPACKAGE:
The arguments to :use set the packages that the package named by package-name will inherit from. If :use is not supplied, it defaults to the same implementation-dependent value as the :use argument to make-package.
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)
将定义一个 'like' CL-USER
的包,因为它使用所有相同的包,并且它将以跨实现工作的方式执行此操作。