プログラミングGauche p.112 delete-1についての練習問題
未だnonLisp脳なせいか、ヒント読んでも分からない。
ごり押しで下のコードができた。一応テストは通るし、末尾再帰なので速い。
(define (my-delete-1 elt lis . options) (define orig-lis lis) (let-optionals* options ((cmp-fn equal?)) (define (loop lis result) (cond [(null? lis) (reverse result)] [(cmp-fn elt (car lis)) (reverse (append (reverse (cdr lis)) result))] [(null? (cdr lis)) orig-lis] [else (loop (cdr lis) (cons (car lis) result))])) (loop lis '())))
これではあんまりだ。でも思いつかないから他の方、emaさんのコードを見る。
(define (delete-1 elt lis . options) (let-optionals* options ((cmp-fn equal?)) (define (loop lis) (cond [(null? lis) lis] [(cmp-fn elt (car lis)) (cdr lis)] [else (let ((memo (loop (cdr lis)))) (if (eq? (cdr lis) memo) lis (cons (car lis) memo)))])) (loop lis)))http://emaame.com/20081025.html
おお、ヒントそのままだw
結果のみを組み込むイメージが掴めた。気がする。emaさん、ありがとうございます。
実行速度
timeマクロで実行速度を測ってみる。
CPUはCore2Duo E7200。
面倒なので計測回数は1回だけ。
計測対象の手続きは、p.111に載ってるdelete-1(コードは最後に載せる)、自分で作った最初のもの、emaさんのの3つ。それぞれwasteful、my、emaと呼ぶ。計測には以下のコードを使った。
(time (delete-1 #t (make-list 1000000 #f)))
評価時間にはtimeマクロが表示するrealの値を使う。結果を以下の表に示す。
手続き | 評価時間(秒) |
---|---|
wasteful | 1.131 |
my | 0.142 |
ema | 0.519 |
意外と差が出るのね。
所でtimeマクロは最後の式の結果を返すので、この場合、巨大なリストが帰ってきてしまう。巨大リストがインタプリタによって表示されてうっとうしいからnull?で捨てるようにしてみた。*1
(null? (time (delete-1 #t (make-list 1000000 #f))))
すると結果は
手続き | 評価時間(秒) |
---|---|
wasteful | 0.466 |
my | 0.147 |
ema | 0.468 |
wasteful変わりすぎ。なんでかしら。
p.111に載ってるdelete-1
(define (wasteful-delete-1 elt lis . options) (let-optionals* options ((cmp-fn equal?)) (define (loop lis) (cond [(null? lis) '()] [(cmp-fn elt (car lis)) (cdr lis)] [else (cons (car lis) (loop (cdr lis)))])) (loop lis)))
*1:もっと手軽な捨て方あるかな?