Posts Tagged ‘functional’
Clojure Macros Simplified
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 user> my-code (println "techbehindtech") user> (eval my-code) techbehindtech
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 ...")
~@body))
user> (def-logged-fn say[name]
(println (str "hello " name)))
#'user/say
user> (say "siva")
Calling ...
hello siva
nil
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/defn
say
[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))))
(def
say
(clojure.core/fn
([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 ...")
~body))
#'user/def-logged-fn
user> (macroexpand-1 '(def-logged-fn say[name]
(println (str "hello " name))))
(clojure.core/defn
say
[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
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
unquote-splicing.
Auto-gensym
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.
Map, Reduce and Filter in Clojure
Map
Map applies a function to each element in a collection and returns a new collection with the results of each function.

user> (map #(+ 10 %1) [ 1 3 5 7 ]) (11 13 15 17)
Reduce
Reduce applies a function on all elements of a collection and returns a value. This value could also be another collection.

user> (reduce * [2 3 4]) 24
Filter
Filter applies a predicate function to each element in a collection and returns a new filtered collection.

user> (filter even? [1 2 3 4 5 6]) (2 4 6)
