SBCL:asdf:定义字符串常量时,load-system失败

时间:2016-01-14 22:27:13

标签: common-lisp sbcl

使用SBCL,当lisp代码定义字符串常量时,我​​遇到了通过ASDF定义的系统无法加载的问题。 这是代码:

constants.lisp

(defconstant A 1.0)
(defconstant B "B")

simple.asd

(defsystem :simple
:components ((:file "constants")))

通过

加载
(asdf:load-system "simple")

我收到以下错误(输出已经缩短了一点):

* (asdf:load-system "simple")  
; compiling file "/Users/.../constants.lisp"
; compiling (DEFCONSTANT A ...)
; compiling (DEFCONSTANT B ...)
; /Users/.../constants-TMP.fasl written
; compilation finished in 0:00:00.003

debugger invoked on a DEFCONSTANT-UNEQL in thread
#<THREAD "main thread" RUNNING {1002BFEA93}>:
   The constant B is being redefined (from "B" to "B")

clisp,ccl和abcl没有出现错误。 另外,通过

加载文件
(load "constants.lisp")

工作正常。

我正在使用

SBCL 1.2.14,ASDF 3.1.3,MacOS

感谢任何提示,

奥利弗

2 个答案:

答案 0 :(得分:8)

为什么字符串常量会失败?

defconstant的规范告诉我们:

  

但是,如果尝试使用其他运算符为符号赋值,或者使用后续的defconstant将其赋值给其他值,则后果是未定义的。

这里重要的词是不同的:根据哪个比较?

  

如果在执行 defconstant 时名称由name命名,或者值 eql 为<的话,则结果不确定。 EM>初始值的

比较由 eql 完成。

SBCL编译您的文件,然后加载结果(xxx-TMP.fasl文件),对于 特定实现,defconstant表单因此被评估两次< / em>在相同的环境中。编译器在编译期间不需要实际评估表单(它可以在内部以某种方式声明,以便可以内联进一步使用常量),但这是一种有效的编译策略。

这里,由于编译环境和加载环境是相同的,并且因为字符串的两个出现相同(不是eq),所以发出错误信号。如果您碰巧使用相同版本的SBCL解释器的另一个实例加载FASL文件,则不会出现此错误。

你能做什么?

  1. 不要重新发明轮子,使用alexandria:define-constant,它允许指定值在哪个测试函数下是常量。 这是一个更精细的版本:

    (defmacro defconst (symbol value)
     `(defconstant ,symbol 
        (or (and (boundp ',symbol) 
                 (symbol-value ',symbol))
            ,value)))
    

    此处,展开的defconstant仍然是顶级形式,我们永远不会使用不eql的内容重新定义它。

  2. 使用defvar,在部署代码之前不再担心(通常需要在开发期间更改常量)。

答案 1 :(得分:0)

感谢大家。切换到亚历山德里亚。