Начал изучение LISP и не понимаю, что происходит при работе setf в моём случае. Пример упрощённый, в реальности всё несколько сложнее.
Есть код:
(dotimes (i 2)
(let ((vec (make-array 0 :fill-pointer 0 :adjustable t)))
(format t "Vector before: ~a~%" vec)
(format t "Pushing: ~a~%" '(1 1))
(vector-push-extend '(1 1) vec)
(format t "Vector after push: ~a~%" vec)
(setf (elt (aref vec 0) 1) 10)
(format t "Vector after setf: ~a~%" vec)
(vector-push-extend '(1 1) vec)
(format t "Vector after push 2: ~a~%" vec)))
При запуске выдаёт следующее.
$ sbcl --script cl.cl
Vector before: #()
Pushing: (1 1)
Vector after push: #((1 1))
Vector after setf: #((1 10))
Vector after push 2: #((1 10) (1 1))
Vector before: #()
Pushing: (1 1)
Vector after push: #((1 10))
Vector after setf: #((1 10))
Vector after push 2: #((1 10) (1 1))
В конце цикла я модифицирую setf'ом первый элемент вектора. Во второй итерации цикла этот элемент оказывается уже модифицированным, хотя вектор другой, итерация другая и элемент я добавляю заново.
Выглядит так, словно на самом деле модифицируется _аргумент_ первого vector-push-extend. Но как он получает доступ к аргументу? Разве каждый раз при записи '(1 1) не должен создаваться _новый_ список из двух единиц? А если не должен, то почему не модифицируются списки '(1 1), передаваемые в format и во второй vector-push-extend?
Где об этом можно вообще почитать? Смотрел в PCL и книжку Грехема, но там о деструктивных операциях с гулькин нос. К тому же, проблема вроде как даже не в деструктивных операциях, а в принципе работы компилятора/интерпретатора.