2

I have created a function to randomly select a 'bit' out of a nested list, e.g., ((1 0 0 1) (1 1 1 1) (0 1 0 1)), and then flip it. If it is a one, make it a zero and vice versa. The function works well, but I have discovered that it mutates the original argument despite my making a copy. Here is the function, the two writes at the end demonstrate this problem. If I pass ((1 1 1 1)) to this, I expect to see this original value printed by (write DNA-seq) but instead the original is modified, so (write DNA-seq) and (write CDNA-seq) print the same thing.

(defun rand-mutate (DNA-seq)
  (let ((CDNA-seq (copy-list DNA-seq)))
    (let ((gene (random-range 0 (length CDNA-seq))))
      (let ((base (random-range 0 (length (nth gene CDNA-seq)))))
        (cond ((= (nth base (nth gene CDNA-seq)) 0) (setf (nth base (nth gene CDNA-seq)) 1))
              (t (setf (nth base (nth gene CDNA-seq)) 0))) (write DNA-seq)(write CDNA-seq)))))
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
Brooks
  • 359
  • 3
  • 9
  • You may find [this answer](http://stackoverflow.com/a/26792893/1281433) to [Changing copies of lists in LISP](http://stackoverflow.com/q/26791982/1281433) useful. – Joshua Taylor Dec 31 '14 at 21:13

1 Answers1

8

copy-list is a shallow copy, it only copies the outermost list, not the lists that each element refers to. Use copy-tree to perform a deep copy.

(defvar list '((1 0 0 1)))
(defvar list-copy (copy-list list))
(defvar list-copy-tree (copy-tree list))
(eq list list-copy) => NIL
(eq (car list) (car list-copy)) => T
(eq (car list) (car list-copy-tree)) => NIL
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thank you for the swift answer, I suspected it would be something simple I was missing. That solved it! – Brooks Dec 31 '14 at 22:03