Macros
Prerequisites: Reading Clojure code, Keywords and symbols
Because Clojure code is made of Clojure data, a function can build
code. A macro is such a function that runs at compile time: it
receives its arguments as unevaluated code and returns new code, which
Clojure then compiles in its place. when, cond, ->, defn, and
for are all macros.
A first macro
(defmacro unless [test & body]
(list 'if test nil (cons 'do body)))
(unless (> 1 2)
(println "1 is not greater than 2")
(println "so this runs"))
(prn (macroexpand-1 '(unless false (println "hi"))))
1 is not greater than 2
so this runs
(if false nil (do (println "hi")))
A function couldn't do this: its arguments would be evaluated before
the call, so both printlns would run regardless of the test. The macro
receives the code itself and decides where it goes. macroexpand-1
shows what a macro call turns into — your main debugging tool.
Syntax quote
Building code with list and cons gets tedious. Syntax quote
(backtick) writes a template:
(defmacro unless [test & body]
`(if ~test nil (do ~@body)))
(unless false (println "templated macro works"))
(prn (macroexpand-1 '(unless false (println "a") (println "b"))))
templated macro works
(if false nil (do (println "a") (println "b")))
`quotes a template and qualifies symbols with their namespace (aprintlnwritten inside the template becomesclojure.core/println), so the expansion means the same thing wherever the macro is used. Special forms likeifanddostay as they are, and the caller's code (~@body) is inserted unchanged.~x(unquote) inserts the value ofx.~@xs(unquote-splicing) inserts the items of a list.
Avoiding name clashes with gensyms
(defmacro with-timing [label & body]
`(let [start# (System/nanoTime)
result# (do ~@body)]
(println ~label "took" (if (< (- (System/nanoTime) start#) 1e9) "under a second" "a while"))
result#))
(def start "user's own start")
(println (with-timing "sum" (reduce + (range 1000))))
(println start)
sum took under a second
499500
user's own start
start# generates a unique symbol (like start__1234__auto__), so the
macro's local names can't collide with the caller's — the user's
start is untouched. This is called hygiene.
A useful macro: a tiny test DSL
(defmacro check [& pairs]
`(do
~@(for [[expr expected] (partition 2 pairs)]
`(let [actual# ~expr]
(println (if (= actual# ~expected) "ok " "FAIL")
(pr-str '~expr) "=>" (pr-str actual#))))))
(check
(+ 1 2) 3
(str "a" "b") "ab"
(count [1 2]) 3)
ok (+ 1 2) => 3
ok (str "a" "b") => "ab"
FAIL (count [1 2]) => 2
'~expr inserts the code of each expression as quoted data, so the
report shows exactly what was tested — something only a macro can do.
The rules of macros
- Don't write a macro when a function will do. Functions compose,
can be passed to
map, and are easier to test. - Use macros for new control flow (
unless,with-retry), binding forms (with-open-style), removing repetitive boilerplate, and compile-time checks or DSLs. - Keep macros thin: have the macro expand into a call to a function that does the real work.
- Always check the expansion with
macroexpand-1/macroexpand.