这是sbcl中的错误吗?

时间:2018-08-29 21:06:38

标签: lisp common-lisp literals sbcl clos

为什么在sbcl中发生这种情况?也许是个错误?

variant

但是如果将:initform更改为:

(defclass myclass ()
  ((s1
    :initform '((a . 1) (b . 2))) 
   (s2
    :initform '((a . 1) (b . 2)))))

(defparameter ins (make-instance 'myclass))

(setf (cdr (assoc 'a (slot-value ins 's1))) 43) ;; change only slot s1

;; here my problem

(slot-value ins 's1)  ;; => ((a . 44) (b . 2)))
(slot-value ins 's2)  ;; => ((a . 44) (b . 2)))

问题消失了

我在 sbcl 1.4.3 1.4.11 中对此进行了测试。似乎没有出现问题。

2 个答案:

答案 0 :(得分:13)

不。您正在修改文字数据,这会带来不确定的后果。

在源代码中引用列表时,这意味着您要使用的内容正是阅读器从源代码生成的列表,这是文字列表。读者可能会记住这些事情,因此不会重复两个相同的列表。

解决此问题的一种方法是在运行时使用listcons创建列表:

(defclass myclass ()
  ((s1
    :initform (list (cons a 1) (cons b 2))) 
   (s2
    :initform (list (cons a 1) (cons b 2)))))

答案 1 :(得分:9)

这不是错误。 '((a . 1) (b . 2))是文字常量,并且所有常量均假定为不可变的。这意味着所有出现的'(a . 1)也是文字的,都可以指向另一个car,因为它永远都不会改变

现在,实现可以选择创建新结构,因此CLISP可以这样做,但是您不能依靠它。您不应变异文字数据。

如果要进行更改,则需要使用深层副本,如下所示:

(defclass myclass ()
  ((s1
    :initform (copy-tree '((a . 1) (b . 2)))) 
   (s2
    :initform (copy-tree '((a . 1) (b . 2))))))