Monday, 2 February 2009

Clojure Macros

Macros are one of the defining features of Lisp languages. A macro operates prior to compilation, allowing you to shape the code as you wish. Since Lisp code is homoiconic the macro language is the language.

Languages like C/C++ have macros, but they are in no way the same. You have a very limited language and you don't get the fine grained access to the code that you do with Lisp (since the code is just itself a Lisp data structure).

Pl Patterns tries to describe a taxonomy of macro use. One of the examples is debug printing with an example from the Arc language. Converted to Clojure this looks like this:


(defmacro dbg-prn
"Debugging form that prints out results"
[& more]
`(let [start# ~more]
(print '~more "==>" start# "\n")
start#))


defmacro defines a new macro with similar structure to defn The ` is used to create a template expression, where we can evaluate certain items within the expression by using macro characters (#,~,`,list-frag?). In this example we used start# to create a uniquely named value for the let expression and ~more to evaluate the parameters.

So now when I'm trying to debug code there's no more repetition of print x, return x I can just edit my function definition by adding dbg-prn (without the normal hardship of wrapping extra brackets around).


user> (dbg-prn + 1 2 3 4 5)
(+ 1 2 3 4 5) ==> 15 ;; printed to std-out
15

user> (dbg-prn + (* 2 3) (* 4 5))
(+ (* 2 3) (* 4 5)) ==> 26
26


You can use macroexpand-1 to expand out macros to see what they actually do:


user> (macroexpand-1 '(dbg-prn + 1 1))
(clojure.core/let [start__2150__auto__ (+ 1 1)]
(clojure.core/print (quote (+ 1 1)) "==>" start__2150__auto__ "\n")
start__2150__auto__)