不同的":cl "包在通用Lisp实现之间的处理方式不同。

问题描述 投票:0回答:1

为什么会发生这种行为?另外,这是一个 "实现定义 "的差异,还是这些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 "中访问。但是 真的很奇怪,三条线会杀死整个语言,所以我还是不清楚。

lisp common-lisp sbcl
1个回答
1
投票

你可以指定包,从包中继承符号,在 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中显式的 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

在一个文件中,通常会使用 :exportdefpackage 形式导出符号,但从 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

3
投票

在CL标准中并没有定义哪种包来访问 使用 当没有 :use DEFPACKAGE中的子句。

CLHS: DEFPACKAGE:

:use的参数设置了由package-name命名的包将继承的包。如果没有提供 :use,则默认为相同的包。依赖于实施的价值 作为make-package的:use参数。

SBCL选择不使用 使用 那么任何包。

传统上其他的CL实现通常会选择 使用 CL包加上一些扩展包。当时的意图是,一个新的包默认为 有用的 用于Lisp编程,如软件包 CL-USER.

对于可移植的代码,你需要指定一个包应该有哪些包。使用. 通常情况下 defpackagemake-package 是要看的运算符。


0
投票

这是对其他答案的补充。

我过去做过的一件事是写一个这样的宏。

(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 在某种意义上说,它使用所有相同的包,并且它将以一种跨实现的方式来实现这一点。

© www.soinside.com 2019 - 2024. All rights reserved.