CDR を変更するための最も低レベルなプリミティブは setcdr です:
この関数は、cons の新しい CDR として object を格納し、それまでの CDR を置き換えます。言い換えれば、cons の CDR スロットを object を指すように変更します。そして、値 object を返します。
以下に、リストのCDRを別のリストに置き換える例を示します。リストの最初の要素を除くすべての要素が削除され、代わりに別の要素列が配置されます。最初の要素はリストのCARに格納されており、CDR経由では到達できないため、変更されません。
(setq x (list 1 2 3))
⇒ (1 2 3)
(setcdr x '(4))
⇒ (4)
x
⇒ (1 4)
リスト内のコンスセルのCDRを変更することで、リストの途中にある要素を削除できます。例えば、ここでは最初のコンスセルのCDRを変更することで、リスト(a b
c)から2番目の要素bを削除します:
(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 |
| | | | | | | | |
-------------- -------------- --------------
以前は要素 b を保持していた2番目の cons セルは依然として存在し、その 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------
| | |
---------------