Clojure Macros for Scheme

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.

Macro #1: ->

clojure.core API reference:

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.

Clojure Implementation

(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)))

Racket Implementation (Straight Port)

(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)))

Racket Implementation (Idiomatic)

(define-syntax-case -> ()
  ((_ x)                 #'x)
  ((_ x (form more ...)) #'(form x more ...))
  ((_ x form)            #'(form x))
  ((_ x form more ...)   #'(-> (-> x form) more ...)))

Macro #2: ->>

clojure.core API reference:

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.

Clojure Implementation

(defmacro ->>
  ([x form] (if (seq? form)
                (with-meta `(~(first form) ~@(next form) ~x) (meta form))
                (list form x)))
  ([x form & more] `(->> (->> ~x ~form) ~@more)))

Racket Implementation (Straight Port)

(define-syntax-case ->> ()
  ((_ x form) (if (stx-list? #'form)
                  #`(#,(stx-car #'form) #,@(stx-cdr #'form) x)
                  #'(form x)))
  ((_ x form . more) #'(->> (->> x form) . more)))

Racket Implementation (Idiomatic)

(define-syntax-case ->> ()
  ((_ x (form more ...)) #'(form more ... x))
  ((_ x form)            #'(form x))
  ((_ x form more ...)   #'(->> (->> x form) more ...)))