TIL

Today I Learned. 知ったこと、学んだことを書いていく

コンスセルとconsとcarとcdr

Lispはすべてリストでできている。また、リストとリストを繋ぐ役目にコンスセルというものがある。これはすごい面白い考え方だと思った

コンスセルは2つの部屋(セル)でできている。1つ目のセル(CARと呼ばれる)にはデータなどを指し、2つ目のセル(CDRと呼ばれる)には別のコンスセルやnilというリストの終わりを示す特別なシンボルを指すことができる。
また、データそのものが入るわけではなく、データの参照を指し示すようになっている。ポインタみたいな?

Lispではコンスセルの連なりとリストは全く同じものとして扱われる。

コンスセルについてはAbout Cons Cellsがわかりやすかった

Lispのプログラムからコンスセルを扱うにはcons関数を使う。ほかにもcarcdrがある。

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

各順番のとおりにadを書けばいいのかも。(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))

あぁ、楽すぎる...まじでやばい