実践CommonLispを読むその9

第十二章 リスト処理:やつらがLISPと呼ぶ理由

ん〜なんかカッコいいタイトルですね。興味がわきます。というよりもここでやっとLISP入門書では一番最初に書いてある、consやcar、cdrが登場するわけですよ。

関数 利用例 意味
cons (cons 1 2) → (1 . 2) 2つの引き数をとり2つの値を保持するコンスセルを返す
car (car (cons 1 2)) → 1 リストの先頭要素を返す
cdr (cdr (cons 1 2)) → 2 リストの先頭要素以外を返す

「cons」で作られるコンスセルってのはリストの最小単位なのかな?コンスセルってのはリストの一部という考え方でええのかや?コンスセルがたくさん集まったものがリストって考え方でええよね。

「car」や「cdr」はコンスセルに対して作用させるが、リストに対しては「first」「rest」を利用した方がよいの?というよりも違いが分からん。同じだと思う。リストに対しても「car」「cdr」を作用させる事ができるし・・・コンスセルとリストに違いはないと思うのだが・・・コンスセルとリストの違いを明確にするため使い分けているのかな?

[0]> (car '(1 2 3 4 5 6 7))
1
[1]> (cdr '(1 2 3 4 5 6 7))
(2 3 4 5 6 7)
[2]> (first (cons 1 2))
1
[3]> (rest (cons 1 2))
2

まあ「cons」は2つの引数しか取れないのが面倒だよね。「cons」でリストを作成する場合は、

[0]> (cons 1 (cons 2 (cons 3 (cons 4 (cons 5 (cons 6 (cons 7 nil)))))))
(1 2 3 4 5 6 7)

LISPのリスト構成を考えれば当然なんだが、めんどいよね。だから「list」関数があるのかな?

そうそうこの章で面白かったのが破壊的な操作かな、

[0]> (defparameter *list-a* '(1 2))
*LIST-A*
[1]> (defparameter *list-b* '(3 4))
*LIST-B*
[2]> (defparameter *list-c* (append *list-a* *list-b*))
*LIST-C*
[3]> (setf (car *list-b*) 0)
(0 4)
[4]> *list-c*
(1 2 0 4)

面白いよね。というか当たり前なんだろうが、「*list-b*」だけを変更したにも関わらず「*list-c*」にも影響を及ぼしている。何でかって言うと、「append」関数がキモで、「append」ってのは「*list-a*」を新しいコンスセルにとり、最後尾、NILになってたのを「*list-b*」の先頭を示すようになっている。つまり「*list-c*」は「*list-b*」を共有しているんですね。へ〜だね。どうせなら2つとも新しくコンスセルを作成し返してくれればいいものを・・・と思ってしまった。

ここさえ理解できればあとは〜いいか!