Previous: Setcdr, Up: Modifying Lists [Contents][Index]
以下ではリストの構成要素であるコンスセルのCDRを変更することにより、リストを破壊的に再配置する関数をいくつか示します。これらの関数が破壊的だという理由は、これらの関数が引数として渡された元のリストを処理してリターン値となる新しいリストを形成するために、リストのコンスセルを再リンクするからです。
コンスセルを変更する他の関数については、Sets And Listsのdelq
を参照してください。
この関数はlistsの要素すべてを含むリストをリターンする。append
(Building Listsを参照)とは異なり、listsはコピーされない。かわりにlistsの各リストの最後のCDRが次のリストを参照するように変更される。listsの最後のリストは変更されない。たとえば:
(setq x '(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 '(1 2 3)) ⇒ (1 2 3)
(nconc x 'z) ⇒ (1 2 3 . z)
x ⇒ (1 2 3 . z)
しかし他の(最後を除くすべての)引数はリストでなければなければならない。
一般的な落とし穴としては、nconc
にたいしてクォートされたリスト定数を最後以外の引数として使用した場合である。これを行なうと、実行するごとにプログラムはリスト定数を変更するだろう!
何が起こるのかを以下に示す:
(defun add-foo (x) ; この関数ではfoo
(nconc '(foo) x)) ; を引数の前に追加したい
(symbol-function 'add-foo) ⇒ (lambda (x) (nconc (quote (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) ⇒ (lambda (x) (nconc (quote (foo 1 2 3 4) x)))