I recently entertained myself by porting two Clojure macros to Racket/Scheme. I present them here hoping they will be useful to somebody more.
Note: The Racket implementations use my convenience macro define-syntax-case
.
Update #1: Asumu Takikawa has implemented the macros using Racket’s new syntax-parse
.
Update #2: Take a look at Rackjure for improved (by yours truly) and packaged implementations of these macros.
->
Usage:(-> x) (-> x form) (-> x form & more)
Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc.
(defmacro ->
([x] x)
([x form] (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x)))
([x form & more] `(-> (-> ~x ~form) ~@more)))
(require (for-syntax syntax/stx))
(define-syntax-case -> ()
((_ x) #'x)
((_ x form) (if (stx-list? #'form)
#`(#,(stx-car #'form) x #,@(stx-cdr #'form))
#'(form x)))
((_ x form . more) #'(-> (-> x form) . more)))
(define-syntax-case -> ()
((_ x) #'x)
((_ x (form more ...)) #'(form x more ...))
((_ x form) #'(form x))
((_ x form more ...) #'(-> (-> x form) more ...)))
->>
Usage:(->> x form) (->> x form & more)
Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc.
(defmacro ->>
([x form] (if (seq? form)
(with-meta `(~(first form) ~@(next form) ~x) (meta form))
(list form x)))
([x form & more] `(->> (->> ~x ~form) ~@more)))
(define-syntax-case ->> ()
((_ x form) (if (stx-list? #'form)
#`(#,(stx-car #'form) #,@(stx-cdr #'form) x)
#'(form x)))
((_ x form . more) #'(->> (->> x form) . more)))
(define-syntax-case ->> ()
((_ x (form more ...)) #'(form more ... x))
((_ x form) #'(form x))
((_ x form more ...) #'(->> (->> x form) more ...)))