copy-list と copy-tree はどう違うのか (Common-Lisp)
『On Lisp』はなかなか難しい。特にコードが難しい。
『部分ツリーでの再帰』のところも、よくわからなかった。
どのリストも二分ツリーとして解釈できる.そのため copy-list と copy-tree 等の Common Lisp の関数の組がある.前者はリストを連続構造としてコピーする.リストが部分リストを含むとき,それは連続構造の要素に過ぎないのでコピーされない:
> (setq x ’(a b) listx (list x 1)) ((A B) 1)
> (eq x (car (copy-list listx))) T
それとは対照的に,copy-tree はリストをツリーとしてコピーする.部分リストは部分ツリーなので,やはりコピーされる:
(引用) 4.6 部分ツリーでの再帰 (“On Lisp”)> (eq x (car (copy-tree listx))) NIL
この箇所、どういう意味なのか、なかなかわからなかった。で、結局こういうことではないかと思う。
前提として、eq関数、equal関数など、以下のようにまとめた(正しいかどうかは自信がない)
(eq A B) -- AとBが、同一オブジェクトである。(メモリ番地も含めてチェックされる)
(eql A B) -- 型、値が同値である。
(equal A B) -- AとBが、同値である。
(= A B) -- AとBが、同値である。型が違っていてもよい。
(参考) 述語 (お気楽 Common Lisp プログラミング入門)
で、『On Lisp』に書かれていた部分を再掲する。
> (setq x ’(a b)
listx (list x 1))
((A B) 1)
listx を図であらわすと、次のようになる。

これを、以下のようにコピーする。
> (setq lst1 (copy-list listx))
> (setq lst2 (copy-tree listx))
このとき、lst1 を図であらわすと、次のようになる。

copy-list では、listxの基礎部分が新しく作られ、もとのlistxの要素がコピーされる。
そして、その car部は、もとのオブジェクトを参照することになる。
したがって、(car lst1)は、もとのオブジェクトを参照しているので、
(eq x (car lst1))
は T となる。
copy-tree では、listxの全体のセル構造が新しくつくられ、すべての要素がコピーされる。
したがって、(car lst2)は、値は同じでも、新しくつくられたオブジェクトなので、
(eq x (car lst2))
は NIL となる。
参考 copy-list, copy-tree, copy-alist
(copy-list)、(copy-alist)、(copy-tree) について、次のサイトにサンプルコードがある。
(参考) Function COPY-TREE (Common Lisp HyperSpec)
サンプルコードは以下。
(setq object (list (cons 1 "one")
(cons 2 (list 'a 'b 'c))))
=> ((1 . "one") (2 A B C))
(setq object-too object) => ((1 . "one") (2 A B C))
(setq copy-as-list (copy-list object))
(setq copy-as-alist (copy-alist object))
(setq copy-as-tree (copy-tree object))
(eq object object-too) => true
(eq copy-as-tree object) => false
(eql copy-as-tree object) => false
(equal copy-as-tree object) => true
(setf (first (cdr (second object))) "a"
(car (second object)) "two"
(car object) '(one . 1)) => (ONE . 1)
object => ((ONE . 1) ("two" "a" B C))
object-too => ((ONE . 1) ("two" "a" B C))
copy-as-list => ((1 . "one") ("two" "a" B C))
copy-as-alist => ((1 . "one") (2 "a" B C))
copy-as-tree => ((1 . "one") (2 A B C))
もとのオブジェクトを変更すると、copy-list したオブジェクトも変更される。
copy-alist の場合も cdr部 が変更される。
copy-treeしたものは、変更されない。
copy-treeは、新しいオブジェクトを作成して、ツリー構造も含めてコピーしている。
copy-alist は、勉強する必要がある。
参考
カテゴリー: Lisp, memo
タグ: common-lisp, copy-alist, copy-list, copy-tree, Lisp
カウント: 180