5.6.3 Функции, переставляющие списки

Ниже приведены функции, которые деструктивно переставляют списки, изменяя CDR их составляющих ячеек конс. Эти функции являются деструктивными, поскольку они изменяют исходные списки, переданные им в качестве аргументов, перелинковывая их ячейки конс для формирования нового списка, который возвращается.

См. delq в Использование списков в качестве множеств для другой функции, изменяющей ячейки конс.

Функция: nconc &списки

Эта функция возвращает список, содержащий все элементы списков. В отличие от append (см. Построение ячеек конс и списков), списки не копируются. Вместо этого последний CDR каждого из списков изменяется, чтобы указывать на следующий список. Последний из списков не изменяется. Например:

(setq x (list 1 2 3))
     ⇒ (1 2 3)
(nconc x '(4 5))
     ⇒ (1 2 3 4 5)
x
     ⇒ (1 2 3 4 5)

Поскольку последний аргумент nconc сам по себе не изменяется, разумно использовать константный список, такой как '(4 5), как в вышеуказанном примере. По той же причине последний аргумент не обязательно должен быть списком:

(setq x (list 1 2 3))
     ⇒ (1 2 3)
(nconc x 'z)
     ⇒ (1 2 3 . z)
x
     ⇒ (1 2 3 . z)

Однако другие аргументы (все, кроме последнего) должны быть изменяемыми списками. Это могут быть списки с точками, чьи последние CDR затем заменяются следующим аргументом:

(nconc (cons 1 2) (cons 3 (cons 4 5)) 'z)
     ⇒ (1 3 4 . z)

Распространенная ошибка — использование константного списка в качестве непоследнего аргумента nconc. Если вы это сделаете, результирующее поведение неопределенно (см. Формы, самовызывающие себя). Возможно, что ваша программа будет вести себя по-разному при каждом запуске! Вот что может произойти (хотя это не гарантировано):

(defun add-foo (x)            ; Мы хотим, чтобы эта функция добавляла
  (nconc '(foo) x))           ;   foo в начало своего аргумента.

(symbol-function 'add-foo)
     ⇒ #f(lambda (x) [t] (nconc '(foo) x))

(setq xx (add-foo '(1 2)))    ; Кажется, работает.
     ⇒ (foo 1 2)
(setq xy (add-foo '(3 4)))    ; Что случилось?
     ⇒ (foo 1 2 3 4)
(eq xx xy)
     ⇒ t

(symbol-function 'add-foo)
     ⇒ #f(lambda (x) [t] (nconc '(foo 1 2 3 4) x))