Common Lisp 实现之间的不同":cl"包处理



为什么会发生这种行为此外,这是"实现定义的"差异,还是这些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(非常有用。

对于可移植代码,您需要指定包应该使用哪些包。通常defpackagemake-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中未使用。您可以通过显式useing包来避免此类问题:

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的包,因为它使用所有相同的包,并且它将以跨实现工作的方式来实现这一点。

最新更新