使用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
感谢任何提示,
奥利弗
答案 0 :(得分:8)
defconstant
的规范告诉我们:
但是,如果尝试使用其他运算符为符号赋值,或者使用后续的defconstant将其赋值给其他值,则后果是未定义的。
这里重要的词是不同的:根据哪个比较?
如果在执行 defconstant 时名称由name命名,或者值 eql 为<的话,则结果不确定。 EM>初始值的
比较由 eql 完成。
SBCL编译您的文件,然后加载结果(xxx-TMP.fasl
文件),对于 特定实现,defconstant
表单因此被评估两次< / em>在相同的环境中。编译器在编译期间不需要实际评估表单(它可以在内部以某种方式声明,以便可以内联进一步使用常量),但这是一种有效的编译策略。
这里,由于编译环境和加载环境是相同的,并且因为字符串的两个出现不相同(不是eq),所以发出错误信号。如果您碰巧使用相同版本的SBCL解释器的另一个实例加载FASL文件,则不会出现此错误。
不要重新发明轮子,使用alexandria:define-constant
,它允许指定值在哪个测试函数下是常量。
这是一个更精细的版本:
(defmacro defconst (symbol value)
`(defconstant ,symbol
(or (and (boundp ',symbol)
(symbol-value ',symbol))
,value)))
此处,展开的defconstant
仍然是顶级形式,我们永远不会使用不eql
的内容重新定义它。
使用defvar
,在部署代码之前不再担心(通常需要在开发期间更改常量)。
答案 1 :(得分:0)
感谢大家。切换到亚历山德里亚。