5.6.3 リストを再配置する関数

以下ではリストの構成要素であるコンスセルのCDRを変更することにより、リストを破壊的に再配置する関数をいくつか示します。これらの関数が破壊的だという理由は、これらの関数が引数として渡された元のリストを処理してリターン値となる新しいリストを形成するために、リストのコンスセルを再リンクするからです。

コンスセルを変更する他の関数については、集合としてのリストの使用delqを参照してください。

Function: nconc &rest lists

この関数はlistsの要素すべてを含むリストをリターンする。append (コンスセルおよびリストの構築を参照)とは異なり、listsコピーされない。かわりにlistsの各リストの最後のCDRが次のリストを参照するように変更される。listsの最後のリストは変更されない。たとえば:

(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)

しかし他の(最後を除くすべての)引数はmutableリストでなければなければならない。これらの引数はドットリストでもよく、その場合にはCDRの最後はは次の引数で置き換えられる:

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

一般的な落とし穴としては、nconcにたいしてリスト定数を最後以外の引数として使用した場合である。これを行なった場合の結果としての挙動は未定義である(自己評価を行うフォームを参照)。実行するごとにプログラムはリスト定数を変更する可能性がある! (必ず発生する保証はないが)以下のようなことが起こり得る:

(defun add-foo (x)            ; この関数ではfoo
  (nconc '(foo) x))           ;   を引数の前に追加したい

(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))
This page has generated for branch:work/emacs-30_69b16e5c63840479270d32f58daea923fe725b90, commit:5e3f74b56ff47b5bcef2526c70f53f749bbd45f6 to check Japanese translation.