修改作为参数传递的列表会在SBCL和CLISP中产生不同的结果

时间:2012-04-28 16:37:37

标签: common-lisp

有人可以解释为什么我使用sbcl和clisp获得以下简单程序的不同结果吗?我正在做什么未被语言定义,或者是两个lisp解释器中的一个错误?

; Modify the car of the passed-in list
(defun modify (a) (setf (car a) 123))

; Create a list and print car before and after calling modify
(defun testit () (let ((a '(0)))
                   (print (car a))
                   (modify a)
                   (print (car a))))
(testit)

SBCL(版本1.0.51)产生:

0 
0 

CLISP(版本2.49)产生(我期望的):

0 
123 

1 个答案:

答案 0 :(得分:2)

我同意Seth和Vsevolod的评论,因为这种行为是由于您修改了文字数据。尝试使用(list 0)代替'(0)。与此相关的问题相对频繁,所以我在这里引用HyperSpec

3.7.1 Modification of Literal Objects

  

如果文字对象是破坏性的,则后果是不确定的   修改。

definition of "literal"

  

字面意思(对象的)直接在程序中引用   而不是由程序计算;也就是说,作为数据出现在   引用表单,或者,如果对象是自我评估对象,则出现   作为未加引号的数据。 ``在形式(cons“one”'(“two”))中,表达式   “一个”,(“两个”)和“两个”是文字对象。''

请注意,通常(在许多实现中),如果您修改文字值,您将真正在代码本身中修改它们 - 编写自修改代码。您的示例代码将无法正常工作。

您在CCL中的示例代码:

CL-USER> (defun modify (a) (setf (car a) 123))
MODIFY
CL-USER> (defun testit ()
           (let ((a '(0)))
             (print (car a))
             (modify a)
             (print (car a))))
TESTIT
CL-USER> (testit)

0 
123 
123
CL-USER> (testit)

123 
123 
123

查看testit的第二次评估,其中let本身确实已包含修改后的值,因此第一个print也会产生123

另请参阅:Lisp, cons and (number . number) difference,我在此更详细地解释了这一点,或者上面的Vsevolod评论中链接的问题。