LINUX.ORG.RU

Деструктивный setf: что происходит?

 


0

1

Начал изучение 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 и книжку Грехема, но там о деструктивных операциях с гулькин нос. К тому же, проблема вроде как даже не в деструктивных операциях, а в принципе работы компилятора/интерпретатора.

★★

Ты модифицируешь «синтаксический» список '(1 1). Он создался один раз при чтении кода. Тебе нужно создавать списки явно в рантайме, используй (list 1 1).

staseg ★★★★★
()
Ответ на: комментарий от staseg

За термин «синтаксический список» прошу отпинать, потом что не знаю, как это назвать правильнее.

staseg ★★★★★
()

Выглядит так, словно на самом деле модифицируется _аргумент_ первого vector-push-extend. Но как он получает доступ к аргументу? Разве каждый раз при записи '(1 1) не должен создаваться _новый_ список из двух единиц? А если не должен, то почему не модифицируются списки '(1 1), передаваемые в format и во второй vector-push-extend?

Эту часть вопроса я пропустил. Другие '(1 1) не модифицируется, потому что они другие (записаны в другом месте).

staseg ★★★★★
()
Ответ на: комментарий от staseg

Спасибо. Помогло :)

А в каких книгах об этом можно почитать глубже?

Очень не хочется изучать язык методом тыка и решая частные случаи/читая stackoverflow :(

pv4 ★★
() автор топика
Ответ на: комментарий от staseg

За термин «синтаксический список» прошу отпинать, потом что не знаю, как это назвать правильнее.

Может, «списковый литерал»?

theNamelessOne ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.