consで作成されるコンスセルでリストは作られる.
コンスセルの前をcar部, 後ろをcdr部を呼び,同名の関数でコンスセルにアクセスできる.
CL-USER> (defvar *x* (cons 1 2))
*X*
CL-USER> (car *x*)
1
CL-USER> (cdr *x*)
2
コンスセルの中でcdr部が他のコンスセルやnilでないものを特別にドットペアと呼ぶ.
;ドットペア
CL-USER> (cons 1 2)
(1 . 2)
;リスト
CL-USER> (list 1 2)
(1 2)
CL-USER> (cons 1 nil)
;リスト
(1)
;(list 1 2)をconsで生成する
CL-USER> (cons 1 (cons 2 nil))
(1 2)
コンスセルをリストとして扱うときにはcar, cdrだけじゃなくfirst, restで扱おうと書いてある.
多分後でそのプログラムを見たときに何を扱っているのかが明確になるからだろうか.
破壊的,非破壊的
appendは最後に与えられた引数以外をコピーして新しいコンスセルを作り,最後の引数をそのコンスセルにくっつける.
最後の引数だけはappendが返すリストと最後の引数ので同じコンスセルを参照するようになる.
破壊的な関数の頭にはNがつくことが多い.
reverseとnreverse, appendとnconc
CL-USER> (defvar *x* (list 1 2 3 4))
(1 2 3 4)
CL-USER> *x*
(1 2 3 4)
CL-USER> (reverse *x*)
(4 3 2 1)
CL-USER> *x*
(1 2 3 4)
CL-USER> (nreverse *x*)
(4 3 2 1)
CL-USER> *x*
(4 3 2 1)
破壊的関数は引数を後で使うつもりがなければ使用してもいい.
たとえば関数内でのレキシカル変数など.
(defun upto (max)
(let ((result nil))
(dotime (i max)
(push i result))
(nreverse result)))
よく使われる組み合わせはsetf, deleteとpush, nreverse.
consp, listp, atom,null
この三つの区別がいまいちわからなかったのでまとめ.
conspはオブジェクトがコンスセルかどうか.
listpはオブジェクトがコンスセルかnilかどうか.
atomはオブジェクトがコンスセルではないかどうか.
nullはオブジェクトがnilかどうか.notと等価だが真偽の評価ではなく空リストのテストとしてはこちらを使うべきらしい
mapcar, maplist
mapcarはリスト専用なのでmapのように型を指定する必要がない.
0 件のコメント:
コメントを投稿