Tech behind Tech

Raw information. No finesse :)

Posts Tagged ‘example

Clojure Macros Simplified

with 5 comments

One of the powerful features of clojure ( or any other LISP) is macros. Macros are so powerful that will allow you do things that you can never do in any other language. There is a classic example of implementing “unless” functionality using macros. I am not going to talk about why we need macros and when to use them. There is so much literature out there discussing about Macros. Also checkout Clojure in Action book for in depth look on Macros. I have read both Joy of Clojure and Clojure in Action, when it comes to Macros I will recommend Clojure in Action. The idea behind this blog to simplify macros as much as possible.

As you know in Clojure code is data and data is code. Our code is a clojure List. So we can programmatically create a list and execute it.

user> (def my-code '(println "techbehindtech"))
user> my-code
(println "techbehindtech")
user> (eval my-code)

In above example, we created a list my-code. This list could be created dynamically. And using eval function we could execute that list as a clojure code.

So to create code in clojure, all we have to do is create a clojure list. In clojure, before a code is evaluated we have hook to introduce our own code using Macros system.

In Macros we are basically creating a list of code similar to my-code. Lets create a simple macro that will allow us to write functions with some log message.

(defmacro def-logged-fn [fn-name args & body]
        `(defn ~fn-name ~args
           (println "Calling ...")
user> (def-logged-fn say[name]
        (println (str "hello " name)))
user> (say "siva")
Calling ...
hello siva

macroexpand and macroexpand-1:

macroexpand and macroexpand-1 are useful functions to know about when using
writing macros. These functions expand our macro forms.

user> (macroexpand-1 '(def-logged-fn say[name]
        (println (str "hello " name))))

 (clojure.core/println "Calling ...")
 (println (str "hello " name)))

You can see that our macro created a fn called “say” that calls println first before the original body. That is pretty cool huh.

The difference between macroexpand-1 and macroexpand is macroexpand-1
will expand only one level of macros and macroexpand calls macroexpand-1
until all macro forms are expanded.

The same macro expanded with macroexpand will look like

(macroexpand '(def-logged-fn say[name]
        (println (str "hello " name))))

   (clojure.core/println "Calling ...")
   (println (str "hello " name)))))

As you can see macroexpand expanded defn macro also.

Coming back to our macro, there are 3 reader macros that we have used

- Backtick `
- Tilda ~
- Tilda Ampersand ~@

Backtick ` (syntax-quote):

This is called as syntax-quote. This quotes the whole expression that way you do not have to quote each one of them

Tilda ~ (unquote):

This is called as unquote. This unquotes (substitutes) the value. For
instance, we wanted to replace fn-name with its value, so we tilda
before fn-name.

Tilda Ampersand ~@ (unquote-splicing):

It is easy to show with an example. Lets take our macro that we wrote and change unquote-splicing to unquote before body and let us what happens.

user> (defmacro def-logged-fn [fn-name args & body]
        `(defn ~fn-name ~args
           (println "Calling ...")
user> (macroexpand-1 '(def-logged-fn say[name]
        (println (str "hello " name))))

 (clojure.core/println "Calling ...")
 ((println (str "hello " name))))

You can see the last line looks wierd. It is trying to call output of
println as a function. This will obiviously fail.

user> (def-logged-fn say[name]
         (println (str "hello " name)))
user> (say "techbehindtech")
Calling ...
hello techbehindtech
; Evaluation aborted.

No message.
  [Thrown class java.lang.NullPointerException]

As body is a list ( we are using varible args) when we just unquote it
is putting body inside a single list. To avoid that we have to


Inside a macro, sometimes you want to create unqualified symbol to use
in a let block. We can do this easily by appending # in end of symbol.

Written by Siva Jagadeesan

September 28, 2010 at 4:32 pm

Posted in Clojure

Tagged with , , , ,


Get every new post delivered to your Inbox.

Join 146 other followers

%d bloggers like this: