deep-copy-list
今、Gauche本こと「プログラミングGauche」を読んでる。7章を読んでいるところ。
- 作者: Kahuaプロジェクト,川合史朗
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/03/14
- メディア: 大型本
- 購入: 22人 クリック: 713回
- この商品を含むブログ (244件) を見る
今回は、6章で取り上げられている、deep-copy-listを書いてみる。
deep-copy-listに先立ってcopy-listという関数が話題に上げられている。
copy-listは次のような関数。
(define copy-list (lambda (l) (if (pair? (cdr l)) (cons (car l) (copy-list (cdr l))) l)))
つまり、引数で与えられたリストをコピーする関数ね。
ただ、cdr部でしか再帰していないので、入れ物だけ新しく用意してる感じ?
僕がこの関数で躓いたのは、再帰の終了条件が
(pair? (cdr l))
ってことかな。はじめ間違って
(if (null? l) l (cons (car l) (copy-list (cdr l))))
ってしてしまった。これじゃ、ドットリストに対応できないからね。
さて、こんなcopy-list関数のあとで、car部分もコピーするdeep-copy-listを作ってみよう、と。
The Little Schemerでいうと、5章に出てきそうな内容かな。
まず、どっかに
(cons (deep-copy-list (car l)) (deep-copy-list (cdr l)))
みたいのが出てくるハズやなー、思って
(define deep-copy-list (lambda (l) (if (pair? (cdr l)) (cons (deep-copy-list (car l)) (deep-copy-list (cdr l))) l)))
って書いてみた。
でも、これじゃ
(deep-copy-list '(foo bar baz))
でソッコー死ぬのね。
具体的には、if式でアトムfooに対してdeep-copy-listを適用しようとして
(cdr 'foo)
で死んどるのね。つまり、
(deep-copy-list (car l))
するつもりなら、
(pair? (car l))
もチェックせざるを得ないわけね。
っちゅうことで、書き直したのがこれ。
(define deep-copy-list (lambda (l) (cons (if (pair? (car l)) (deep-copy-list (car l)) (car l)) (if (pair? (cdr l)) (deep-copy-list (cdr l)) (cdr l)))))
でも、これ、なんかキモい。(直感的に。直感はあてにならないけど。)
2個あるif式の構造がおんなじなので、まとめることができるのは分かる。
けど、まとめたとしても、なんかキモい。自分でも何がキモいかわからんけど、なんとなくキモい。
ということで、とりあえず共通な部分をローカルな関数でまとめた結果を書いとく。
(define deep-copy-list (lambda (l) (define f (lambda (g l) (if (pair? l) (g l) l))) (cons (f deep-copy-list (car l)) (f deep-copy-list (cdr l)))))