Strange behavior that calls a destructive common LISP function, receiving as an argument a list created using a quote

I get strange behavior when calling a destructive definition that takes as argument an local variable whose type is a list created with a quote .

Destructive function:

(defun insert-at-pos (pos list elem) (if (= pos 0) (cons elem list) (let ((aux-list (nthcdr (1- pos) list))) (setf (rest aux-list) (cons elem (rest aux-list))) list))) 

WRONG: A local variable is a list created by a special quote statement.

 (defun test () (let ((l '(1 2 3))) (print l) (insert-at-pos 2 l 4) (print l))) > (test) (1 2 3) (1 2 4 3) (1 2 4 3) > (test) (1 2 4 3) (1 2 4 4 3) (1 2 4 4 3) > (test) (1 2 4 4 3) (1 2 4 4 4 3) (1 2 4 4 4 3) 

CORRECT: A local variable is a list created using the list function.

 (defun test2 () (let ((l (list 1 2 3))) (print l) (insert-at-pos 2 l 4) (print l))) 

or

 (defun test2 () (let ((l '(1 2 3))) (print l) (setf l (cons (first l) (cons (second l) (cons 4 (nthcdr 2 l))))) (print l))) > (test2) (1 2 3) (1 2 4 3) (1 2 4 3) > (test2) (1 2 3) (1 2 4 3) (1 2 4 3) > (test2) (1 2 3) (1 2 4 3) (1 2 4 3) 

Does anyone know the reason for this strange behavior?

+1
list lisp common-lisp quote
source share
1 answer

If you specify data in a function, then this is literal data. The effects of the destructive modification of such data are undefined in the Lisp standard. In your example, all function calls use the same literals, and the implementation does not warn you that you are changing it. This is what most implementations do. But you can also imagine an implementation that puts all of the code (and its literals) into a read-only part in memory.

You can get funky effects with this.

If you want to destructively modify the list without encountering potential problems, you need to create a new copy at runtime. For example, calling LIST or COPY-LIST . LIST will return a new list.

There are similar pitfalls. For example, imagine a file with these definitions:

 (defvar *foo* '(1 2 3 4 5 6 ... 10000)) (defvar *foo* '(0 1 2 3 4 5 6 ... 10000)) 

If you compile such a file using a file compiler, the compiler is allowed to create a compiled file in which these two variables share a literal space for storing data. If you change an item in any list, both can be changed.

+8
source share

All Articles