The reason why destructive oprations can be dangerous is that if variables share list elements like in the following example:
Code: Select all
(defparameter x (list 0 1 2 3))
(defparameter y (cdr x))
x => (0 1 2 3)
y => (1 2 3)
The pointers of the CONS cells in memory look like this:
Code: Select all
Y -------------------,
+-----+-----+ | +-----+-----+ +-----+-----+ +-----+-----+
| | | '->| | | | | | | | |
X --->| 0 | *------->| 1 | *------->| 2 | *------->| 3 | *------> NIL
| | | | | | | | | | | |
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
If you now (setf x (nreverse x)), what will be the value of Y afterwards?
Code: Select all
Y -------------------,
,-----------------------------------------------------,
| +-----+-----+ | +-----+-----+ +-----+-----+ | +-----+-----+
| | | | '->| | | | | | | | | |
X -' | 0 | * | ,->| 1 | * | ,->| 2 | * | '->| 3 | * | ,->NIL
,->| | | | | | | | | | | | | | | | | | |
| +-----+--|--+ | +-----+--|--+ | +-----+--|--+ +-----+--|--+ |
| | | | '-----------------------------' |
| | '-----------------------------' |
'-----------------------------' |
'-----------------------------------------------------------'
The answer is that X has been properly NREVERSEd, but Y now suddenly contains elements that it didn't contain before:
In such cases either
REVERSE instead of NREVERSE (where REVERSE makes a copy of the list), or
COPY-LIST can be used like this:
Code: Select all
(defparameter x (list 0 1 2 3))
(defparameter y (cdr (copy-list x)))
CLISP History
In the very early days CLISP was developed to run the
Maxima Computer Algebra System on standard home computers in a terminal window with a command history and cursor control. This was in the 1990s, when home computers had only a few megabytes of memory. Because Maxima makes heavy use of lists for math computations, it probably was most important not to waste memory for list operations. I'm no CLISP developer but I think this is one of the reasons for the unusual behaviour of NREVERSE in CLISP.
- edgar