Самый низкоуровневый примитив для изменения CDR — это setcdr:
Эта функция сохраняет object как новый CDR для cons, заменяя его предыдущий CDR. Другими словами, она меняет CDR ячейку cons так, чтобы она указывала на object. Она возвращает значение object.
Вот пример замены CDR списка другим списком. Все элементы, кроме первого, удаляются в пользу другой последовательности элементов. Первый элемент не изменяется, потому что он находится в CAR списка, и не достигается через CDR.
(setq x (list 1 2 3))
⇒ (1 2 3)
(setcdr x '(4))
⇒ (4)
x
⇒ (1 4)
Вы можете удалить элементы из середины списка, изменяя CDR ячеек cons в списке. Например, здесь мы удаляем
второй элемент, b, из списка (a b c), изменяя CDR первой ячейки cons:
(setq x1 (list 'a 'b 'c))
⇒ (a b c)
(setcdr x1 (cdr (cdr x1)))
⇒ (c)
x1
⇒ (a c)
Вот результат в блочной нотации:
--------------------
| |
-------------- | -------------- | --------------
| car | cdr | | | car | cdr | -->| car | cdr |
| a | o----- | b | o-------->| c | nil |
| | | | | | | | |
-------------- -------------- --------------
Вторая ячейка cons, которая ранее содержала элемент b, все еще существует, и ее CAR все еще b, но она больше не является частью этого списка.
Настолько же легко вставить новый элемент, изменив CDR:
(setq x1 (list 'a 'b 'c))
⇒ (a b c)
(setcdr x1 (cons 'd (cdr x1)))
⇒ (d b c)
x1
⇒ (a d b c)
Вот этот результат в блочной нотации:
-------------- ------------- -------------
| car | cdr | | car | cdr | | car | cdr |
| a | o | -->| b | o------->| c | nil |
| | | | | | | | | | |
--------- | -- | ------------- -------------
| |
----- --------
| |
| --------------- |
| | car | cdr | |
-->| d | o------
| | |
---------------