#:g1: ClojureでL-99 (P08 リストの圧縮)

Posted 2008-09-24 19:55:00 GMT

今回は、letのリストの分割束縛機能を無理矢理気味に使ってみました。テストのところもなんとなくマクロに。

(defn 
#^{:doc "P08 (**) Eliminate consecutive duplicates of list elements."
:test (test= (compress '(a a a a b c c a a d e e e e))
'(a b c a d e))}
; --------
compress [coll]
; --------
(loop [coll coll, acc `[~(gensym)] ]
(let [[head & tail] coll]
(cond
(empty? coll)
(rest (reverse acc))
;;
(= head (first acc))
(recur tail acc)
;;
:else
(recur tail (cons head acc))))))

(defmacro test= [expr val]
`(do (assert (= ~expr ~val))))
Clojureでは、,(コンマ)ではなく、~でクオート解除になります。コンマは空白として扱われるので、変数束縛の部分等でみやすく清書するために使えます。
また、ClojureはLISP-1ということもあり、古典的なマクロでは、展開先で内部で使用している関数(マクロ)が書き換えられてしまう問題が心配されますが、これは回避してくれるとのこと。CLのように名前空間も分かれているので(CLのパッケージ的)この点でもScheme+古典的マクロより安全そうです。
(let [= list]
  (= 3 3))
;=> (3 3)

(defmacro foo [x] `(= ~x ~x))

(let [= list] (foo 3)) ;=> true ; 意図した通りの動作

;; scheme (Gauche等) (define-macro (foo x) `(= ,x ,x))

(let ((= list)) (foo 3)) ;=> (3 3) ; 書き換えられてしまいました。


comments powered by Disqus