I am defining a variable as a list containing lists of symbols:
(defparameter *var* '((a a a) (a x a) (a a a)))
When I try to change one of the elements with setf
...
(setf (caar *var*) 'c)
... both the first and the last lists are updated.
> *var*
; ((c a a) (a x a) (c a a))
I noticed that when I evaluate the defparameter
in the REPL, the setf
command works as expected. This makes me think that the unexpected behaviour is related to the compilation process.
Questions:
What is happening and why?
What would be the canonical way of defining a list of fresh lists containing the same symbols in defparameter
?
I am using SBCL.
Edit: My question is not similar to this question, because I am not asking how to copy lists so that they do not share structure, but rather why when compiling a defparameter
lists with similar elements appear to share structure and how to define them so they do not.
This is a frequently asked question.
Why does SBCL show this implementation dependent behavior?
Try after loading the compiled file (use COMPILE-FILE
to compile it):
* (eq (first *var*) (third *var*))
T
* *var*
((A A A) (A X A) (A A A))
* (setf *print-circle* t)
T
* *var*
(#1=(A A A) (A X A) #1#)
*
Above shows that the first and third sublists are the same.
Running it in the REPL is left as an exercise. It may show different results.
In ANSI Common Lisp the File Compiler is allowed to coalesce similar list data. (a a a)
and (a a a)
are similar. This may save memory space in a compiled program. Not every Common Lisp implementation does that, but SBCL does it. Remember, when the book Common Lisp the Language, 1st edition was published in 1984, the first Apple Macintosh had just 128KB RAM.
Solution: use COPY-TREE
:
To create a fresh & non coalesced copy of the nested list use the function COPY-TREE
. Fresh means that it is not literal data and thus one is allowed to modify it. COPY-TREE
copies all levels of a cons tree, COPY-LIST
only copies the top list. Since your data is nested, we need COPY-TREE
:
(defparameter *var*
(copy-tree '((a a a) (a x a) (a a a))))