mphilli
mphilli

Reputation: 25

Lisp: How to stop unwanted reassignment of multiple list variables

In lisp, I have the following example code:

(setf list1 '("a" "b" "c" )) 
(setf list2 '())
(setf list2 list1)
(setf (nth 2 list1) "d")
(princ list1)
(princ list2)

I want the result to be:

(a b d)(a b c)

but it instead reassigns the nth element of both 'list1' AND 'list2', resulting in:

(a b d)(a b d) 

I'm assuming it's because I set list2 equal to list1 earlier in the code, but usually when you set variables equal to one another, they don't change like that. What's going on here?

Upvotes: 0

Views: 61

Answers (2)

Jason
Jason

Reputation: 1069

When you assign lists in lisp, no copying happens. The third line from your question:

(setf list2 list1)

does not copy the list, but rather sets list2 to also refer to the same cons cell as list1. If you want a fresh list, instead use copy-list:

(setf list2 (copy-list list1))

Which will set list2 to be a shallow copy of list1; that is to say that all the CARs of the CONS cells in list1 and list2 will be the same.

Upvotes: 3

mphilli
mphilli

Reputation: 25

In case no one is able to help me, I came up with a solution to override the issue, although it's not very elegant:

(setq list1 '("a" "b" "c")) 
(setq list2 '())
(setq i 0) 
(loop 
(setf list2 (append list2'(0)))
(setf (nth i list2)(nth i list1))
(setq i (+ i 1))
(when (= i (list-length list1)) (return)))
(setf (nth 2 list1) "d")
(princ list1)
(princ list2)

Still very curious why (setf (nth N L) T) resets the nth element of all lists whose values have been equated using set.

Upvotes: 0

Related Questions