<cl> (defstruct test a b) TEST <cl> (setq a (list (make-test :a '(a) :b '(b)) (make-test :a '(a) :b '(b)))) (#s(TEST :A (A) :B (B)) #s(TEST :A (A) :B (B))) <cl> (setq b (make-test :a '(a) :b '(b))) #s(TEST :A (A) :B (B)) <cl> (setq c (list b b)) (#s(TEST :A (A) :B (B)) #s(TEST :A (A) :B (B))) <cl> (eq (car a) (cadr a)) NIL <cl> (eq (car c) (cadr c)) T <cl> (eql (car a) (cadr a)) NIL <cl> (equal (car a) (cadr a)) NIL <cl> (equalp (car a) (cadr a)) T一般に構造体でグラフを表現する場合に,頂点の構造体のコピーを作らなけれ ば,構造体の比較はeqで可能になります. そこで,以下のように構造体のコピーを作らないようにグラフを作りました.
(defstruct graph vlist elist) (defstruct vertex name alist) (defstruct edge vertex1 vertex2) (defun graph-structure (&optional (gel *graph-edge-list*)) (let ((gvl (mapcar #'(lambda (v) (make-vertex :name v)) (graph-vlist gel))) (graph nil)) (setq graph (make-graph :vlist gvl :elist (mapcar #'(lambda (e) (make-edge :vertex1 (find (car e) gvl :key #'vertex-name) :vertex2 (find (cadr e) gvl :key #'vertex-name))) gel))) (dolist (vl (graph-vlist graph)) (mapc #'(lambda (av) (push (find av (graph-vlist graph) :key #'vertex-name) (vertex-alist vl))) (vertex-adjacency-list-from-elist (vertex-name vl) gel))) graph))以下のように実行すると,頂点sに対応する構造体のalistには,頂点dが入っ ていることがわかります.つまりdへのポインタが入っているわけで,コピー へのポインタが入っているわけではないということがわかります.コピーへの ポインタならば(find d (vertex-alist s) :test 'eq)はnilになってしまい, そのnotはTになってしまいます.
<cl> (setq vl (graph-vlist *graph6*)) <cl> (setq s (find 's vl :key #'vertex-name)) <cl> (setq d (find 'd vl :key #'vertex-name)) <cl> (not (find d (vertex-alist s) :test 'eq)) NIL今まで頂点として使ってきたシンボルはコピーが作られる心配がありませんで した.それは,Lispの処理系がシンボル名を読み込んだときに,すでに使われ たシンボルの登録表の中からそのシンボル名をもつシンボルを毎回探しだし, そのシンボルへのポインタを返すようにしているからです. 構造体データの生成がそのようにコピーを作らない生成方法になっていたなら ば,上のように作らずとも必要となったところでmakeをすればよいということ になります.しかし,Lispのオブジェクト空間の中から構造体の内部のequalp を調べるというのは大変な処理になってしまいます.また,コピーが必要な場 合に困ってしまうため,このような形になっています.