【Common Lisp】リストの基本中の基本
リストはLispにおいて非常に大事です。ということで、Common Lispのリストの基本的なアイデアをまとめました。
フォーム
Lispのコードはリストで構成されています。このリストは、フォームでなければなりません。フォームとは、先頭の要素がコマンドであるようなリストのこと。
コマンドの厳密な意味をまだ理解できていないのですが、多くの場合関数であるようです。
コードモードとデータモード
Common Lispのプログラムには次の2つのモードがあります。
- コードモード:実行される。フォーム。
- データモード:実行されない単なるデータ。
デフォルトではコードモードとなっています。データモードにするにはリストの前にシングルクオートをつけます(この操作を「クオートする」という)。
例:
CL-USER> (expt 2 3) 8 CL-USER> '(expt 2 3) (EXPT 2 3)
上のコードモードは2の3乘を計算していますが、下のデータモードでは式をそのまま返しています。
準クオートと呼ばれる機能を使うと、データモードの中にコードモードの部分を埋め込むこともできます。
バッククオートでデータモードになり、カンマでコードモードになります。
CL-USER> `(1 + 1 = ,(+ 1 1)) (1 + 1 = 2)
リストの構造
コンスセル
Lispのリストは、コンスセルと呼ばれる部品からなっています。コンスセルは、2つのセルを並べたような構造をしています。それぞれのセルは何らかの別のものをさし示しています。
例えば、'(1 2 3)は次のようになっています。
一つ目のセルはデータを、2つ目のセルが次のコンスセルを指しています。nilはリストの終端を表しています。
連結リストに似ていますね。
リストを操作する
cons関数
cons関数は2つのデータをくっつけたリストを作ります。
例:
CL-USER> (cons 'chicken 'cat) (CHICKEN . CAT) CL-USER> (cons 'chicken 'nil) (CHICKEN) CL-USER> (cons 'chicken ()) (CHICKEN) CL-USER> (cons 'pork '(beef 'chicken)) (PORK BEEF 'CHICKEN)
リストの真ん中のドットは、それがコンスセルであることを表現しています。nilは空リストと等価であり、上のように省略されます。
次の表現は全て等価です。
上の図の'(1 2 3)は次のようになります。
CL-USER> (cons 1 (cons 2 (cons 3 ()))) (1 2 3)
コンスセルが連なっているのが、リストとして表示されています。
car、cdr
car関数はリストの最初のコンスセルの1番目のセルの指すものを取り出します。
cdr関数はリストの最初のコンスセルの2番目のセルが指すものを取り出します。つまり、リストで言えば、2番目以降の要素が取り出されることになります。
CL-USER> (car '(pork beef chicken)) PORK CL-USER> (cdr '(pork beef chicken)) (BEEF CHICKEN)
carとcdrを組み合わせたコマンドに、cdarやcadrなどがある。それぞれ、carを適用してからcdrを適用したもの、cdrを適用してからcarを適用したもの。
list
list関数を使うと、cons関数を重ねて用いなくても、長いリストを簡単に作ることができます。
CL-USER> (list 'pork 'beef 'chicken) (PORK BEEF CHICKEN)
まとめると、リストの作り方には、list関数を使う、consしてコンスセルをつなげる、クオートして作る、という3つの方法があります。
append
append関数はいくつかのリストをまとめて1つのリストにします。
CL-USER> (append '(mary had) '(a) '(little lamb)) (MARY HAD A LITTLE LAMB)
参考
コンラッド・バルスキ(2013)「Land of Lisp」 川合史郎訳 オライリー・ジャパン