2010-12-20

cond-cons

Scheme:マクロの効用リストの構築で、cond-consというマクロが紹介されてるけど、Common Lispで欲しくなったので書いてみた。

(defmacro cond-cons (&rest clauses)
  (labels ((rec (clauses)
             (if clauses
                 (let ((clause (car clauses))
                       (r (rec (cdr clauses))))
                   `(if ,(car clause) (cons (progn ,@(cdr clause)) ,r) ,r))
                 nil)))
    (rec clauses)))

一瞬、rが複数回評価されて、副作用があるとまずいんじゃ、とか思ったけど、考えたらifで分岐するから問題なかった。

マクロなのに末尾再帰版。すみません。大好きです末尾再帰。

(defmacro cond-cons (&rest clauses)
  (labels ((rec (clauses fn)
             (if clauses
                 (let ((clause (car clauses)))
                   (rec (cdr clauses)
                        (lambda (x)
                          `(if ,(car clause)
                               (cons (progn ,@(cdr clause)) ,(funcall fn x))
                               ,(funcall fn x)))))
                 `(nreverse ,(funcall fn nil)))))
    (rec clauses (lambda (x) x))))

コンパイル時にしか評価されないので、ほとんど意味がない。末尾再帰じゃないバージョンだとスタックが溢れるくらい、clausesが長いリストだったりするなら多少は意味があるだろうけど、それってどんなだよ。

Paul Grahamも同じ趣旨のことをOn Lispかどこかに書いてたように思うけど、マクロ定義のコードで頑張る意味なんてない。

ちなみに、Gaucheでは、util.listにcond-listという名前で、より高機能なものが収録されている。何でそんなことを書くかというと、以前探したときに、しばらく見付けられなかったからではない。そんなわけはない。

0 件のコメント: