clojureのカスケードマクロを導入

昨日書いていたコードの中でassoce-default相当の関数を書こうとした際に、
clojureの-?>が使いたくなった。-?>は結果をみて偽なら実行を途中で打ち切るという点ではand-let*と同様、
でもand-let*とは異なり結果に特に名前をつけたくないような場合に使いたくなる。
これがあるとassoc-defaultは以下のように書ける。

(define (assoc-default e alist) ;;elispなどにある
  (-?> (assoc e alist) cadr))

(assoc-default 'x '((x 10) (y 20) (z 30))) ; => 10
(assoc-default 'i '((x 10) (y 20) (z 30))) ; => #f

code

(use util.match)
(define-macro (-> init . rest)
  (fold (lambda (xs acc)
          (match xs
            [(fn . args) `(,fn ,acc ,@args)]
            [fn `(,fn ,acc)]))
        init rest))

(define-macro (->> init . rest)
  (fold (lambda (xs acc)
          (match xs
            [(fn . args) `(,fn ,@(append args (list acc)))]
            [fn `(,fn ,acc)]))
        init rest))

(define-macro (-?> init . rest)
  (let1 tmp (gensym)
    (fold (lambda (xs acc)
            (match xs
              [(fn . args) 
               `(let1 ,tmp ,acc
                  (and ,tmp (,fn ,tmp ,@args)))]
              [ fn `(let1 ,tmp ,acc (and ,tmp (,fn ,tmp)))]))
          init rest)))

;; (macroexpand '(-> 10))
;; (macroexpand '(->> 10))
;; (macroexpand '(-?> 10))
;; (macroexpand '(-> 10 (+ 2) (- 3)))
;; (display (unwrap-syntax (macroexpand '(-?> 10 (+ 2) (- 3)))))
;; (macroexpand '(->> 10 (+ 2) (- 3)))