emacs lisp にも clojure の ->> が欲しいよね

試しに書いてみたんだけど、これはいいかも...

(require 'cl)

(defmacro my:-> (&rest exprs)
  (when exprs
    (reduce
     '(lambda (acc expr)
        (if (listp expr)
            (cons (car expr) (cons acc (cdr expr)))
          (list expr acc)))
     exprs)))

(defmacro my:->> (&rest exprs)
  (when exprs
    (reduce
     '(lambda (acc expr)
        (if (listp expr)
            (append expr (list acc))
          (list expr acc)))
     exprs)))

(defmacro my:flip (f a b)
  `(,f ,b ,a))

実行例

(my:->> (loop for x from 1 to 5 collect x)
        (mapcar '(lambda (x) (* x x)))
        (apply '+)
        (my:flip / 2.0))
;;=> 27.5
(my:->> (my:-> (loop for x from 1 to 50 by 2 collect x)
               (subseq 10 20))
        (mapcar 'number-to-string)
        (reduce '(lambda (acc x) (concat acc "," x))))

;;=> "21,23,25,27,29,31,33,35,37,39"

注意点

lisp-2 の elisp では関数を高階関数に渡す場合クォートが必要で、マクロに渡す場合はクォート不要です。ちょっと紛らわしい。上の例では、 my:flip がマクロなので除算関数 / にはクォートが不要。もし my:flip が関数だったら '/ としなければならない。

なお clojure とは実装が違うので挙動はまったく同じではないです。clojure の -> は無引数だとエラーになりますが、 my:-> はエラーにはならず nil になります。他にも違いがあるかも。