This article is the last part of our Clojure macros tutorial. The previous parts were:

Now we are going to show you how clojure ninjas write macros.

The disp macro - by 2 anonymous ninjas

The disp macro receives expressions and returns a symbol with the expressions and their respective evaluations. (A symbol is much more pretty than a string.)

(ns my.best$macros) (defn symbol-several "returns a symbol with the concatenation of the str values of the args" [& x] (symbol (apply str x))) (defmacro disp [& forms] (cons `symbol-several (for [form forms] `(str '~form " => " ~form "

")))) (my.best/disp (map inc [1 2 3]) (+ 4 5 6))

Two smart guys on Clojurians Slack helped me to write the disp macros.

The defprint macro - by Herwig Hochleitner

The defprint macro defines a function with a tweak: each time the function is called, it prints the values of its arguments. The tricky part is that it works also with desctructuring.

(ns my.best$macros) (defmacro defprint [func-name args & body] `(defn ~func-name [& args#] (print '~func-name "called with: " args#) (let [~args args#] ~@body))) (my.best/defprint foo [a b c] (+ a b c)) (foo 1 2 3)

And here is what is printed in when foo is called:

(with-out-str (foo 1 2 3))

Another example, with arguments desctructuring:

(my.best/defprint hello-world [& {:keys [language] :or {language :en}}] (case language :fr "bonjour monde" :en "hello world")) (hello-world :language :fr)

(with-out-str (hello-world :language :fr))

And here is the code generated by the macro:

(macroexpand-1 '(my.best/defprint foo [& {:keys [language]} :or {language :en}]))

Take a couple of minutes to meditate on the power of this part of the macro:

( let [ ~ args args # ] ~@ body )

Herwig Hochleitner helped me to write the defprint macro.

You can read more about desctructuring.

The doseq-indexed macro - by Tim Baldridge

doseq-indexed works like doseq with an additional binding to the index.

Tim Baldridge ( core.async author) wrote an elegant implementation for doseq-indexed :

(ns my.best$macros) (defmacro doseq-indexed [index-sym [item-sym coll] & body] `(doseq [[~item-sym ~index-sym] (map vector ~coll (range))] ~@body)) (with-out-str (my.best/doseq-indexed i [x [10 100 1000]] (println "i: " i "x: " x)))

Here is Tim’s original gist.

Feel free to share your favorite macros in the comments below.

Clojure rocks!