コンスセルとconsとcarとcdr
Lispはすべてリストでできている。また、リストとリストを繋ぐ役目にコンスセルというものがある。これはすごい面白い考え方だと思った
コンスセルは2つの部屋(セル)でできている。1つ目のセル(CARと呼ばれる)にはデータなどを指し、2つ目のセル(CDRと呼ばれる)には別のコンスセルやnil
というリストの終わりを示す特別なシンボルを指すことができる。
また、データそのものが入るわけではなく、データの参照を指し示すようになっている。ポインタみたいな?
Lispではコンスセルの連なりとリストは全く同じものとして扱われる。
コンスセルについてはAbout Cons Cellsがわかりやすかった
Lispのプログラムからコンスセルを扱うにはcons
関数を使う。ほかにもcar
とcdr
がある。
cons関数
> (cons 1 2) (1 . 2)
これは、1と2をコンスセルで繋いでいますよっていうこと。リストと区別するために、.
が入っている
> (cons 1 'nil) (1)
第2引数にリストの終りを示す'nil
を渡すと、通常のリストのような表示になる。(1 . 'nil)
と同じ意味。Lispはできるだけ、コンスセルではなくリストとして見せてくれている!
> (cons 1 ()) (1)
Common Lispでは、空のリスト()
とシンボル'nil
は同じ意味となっている。そのためこのようにも書ける。
「空のリストに1を追加したら、1だけのリストになる」と考えればしっくりきた。
どんなリストもコンスセルで表せる!
> '(1 2 3) (1 2 3) > (cons 1 (cons 2 (cons 3 'nil))) (1 2 3) > (cons 1 (cons 2 (cons 3 ()))) (1 2 3)
car関数とcdr関数
コンスセルを扱うための関数であるcar(カー)とcdr(クダー)。それぞれ、コンスセルの部屋の構造と一致している。
car
で1つ目のコンスセルのCARセル。cdr
で1つ目のコンスセルに紐づくデータが取得できる。
> (car '(dog cat chicken)) DOG > (cdr '(dog cat chicken)) (CAT CHICKEN) > (cdr (cons 'b 'nil)) NIL
組み合わせることで取得したい場所を取得できる。ちょっと複雑になるけど。。。
例)2番目の要素を取得する
> (car (cdr '(dog cat chicken))) CAT
cdr
で2番目以降の要素を取得し、それに対してcar
で1番目の要素(2番目)を取得する
一度に取得できる関数も用意されている
> (cadr '(dog cat chicken)) CAT > (cadr '(dog cat chicken)) CAT > (cddr '(dog cat chicken)) (CHICKEN) > (caddr '(dog cat chicken)) CHICKEN > (cdddr '(dog cat chicken)) NIL
各順番のとおりにa
かd
を書けばいいのかも。(car (cdr '(...)))
だから、(cadr '(...))
みたいに。
最後のコンスセルにはnilが入っていることを忘れずに!!!
cdadadr
をやろうとしたら、そんなの無いよ!!!っていわれた。最大4つまでらしい。
> (cdadadr '((peas carrots tomatoes) (pork beef chicken))) *** - EVAL: undefined function CDADADR
list関数
list関数を使うと簡単にリストが作れる。
以下の3つは同じ意味!!
> (list 'dog 'cat 'chicken) (DOG CAT CHICKEN) > '(dog cat chicken) (DOG CAT CHICKEN) > (cons 'dog (cons 'cat (cons 'chicken ()))) (DOG CAT CHICKEN)
nilを含まないデータでcdrを使うと
なんかおもしろいと思った。
> (cons 'a (cons 'b 'c)) (A B . C) > (cdr (cons 'a (cons 'b 'c))) (B . C) > (cddr (cons 'a (cons 'b 'c))) C
.
は要素なのかな!?って思ってみたけど、そんなことはなかった。。。
listとクオートの快適さを実感した
複雑なリストを作るときにちょっと手こずった。
> (cons (cons 'peas (cons 'carrots (cons 'tomatoes ()))) (cons 'pork (cons 'beef (cons 'chicken ())))) ((PEAS CARROTS TOMATOES) PORK BEEF CHICKEN)
((PEAS CARROTS TOMATOES) (PORK BEEF CHICKEN))
ってなってほしい!!
> (cons (cons 'peas (cons 'carrots (cons 'tomatoes ()))) (cons (cons 'pork (cons 'beef (cons 'chicken ()))) ())) ((PEAS CARROTS TOMATOES) (PORK BEEF CHICKEN))
できたけど、ややこしいよ!!!!!!
これをやったあとにlist
やクオートを使うとなんと楽なことか
> (list (list 'peas 'carrots 'tomatoes) (list 'pork 'beef 'chicken)) ((PEAS CARROTS TOMATOES) (PORK BEEF CHICKEN)) > '((peas carrots tomatoes) (pork beef chicken)) ((PEAS CARROTS TOMATOES) (PORK BEEF CHICKEN))
あぁ、楽すぎる...まじでやばい