I kind of understand Clojure macros
Looks like I have understood about macros in Clojure (a bit). So whats a macro? Lets say you want to add 2 and 3 and you will write it like this:
(+ 2 3)
Where +
is a function and 2
and 3
are arguments. But let’s say that I am more comfortable writing it as (2 + 3)
rather than (+ 2 3)
, how I can do that in Clojure?
When you consider any Clojure code like (+ 2 3)
its basically a list, you can verify it in REPL as shown
user=> (type '(+ 2 3))
clojure.lang.PersistentList
The single quote here '(+ 2 3)
tells to Clojure that not to execute the list. The basic thing is, any program in Clojure is a list. So even (2 + 3)
is a list. Now all we need to do is convert (2 + 3)
to (+ 2 3)
and let it execute.
So let’s imagine we capture (2 + 3)
in a variable called a-list
. We take the first element:
(first a-list) ; This gets the 2
Then after the first we put the last element:
(first a-list) ; This gets the 2
(last a-list) ; This gets the 3
We need to grab the plus sign and put it in front, and we see the plus is in the middle of a-list
which is (2 + 3)
, that is the +
is the second element:
(second a-list)
(first a-list) ; This gets the 2
(last a-list) ; This gets the 3
Now we pack it into a list:
(list ; convert (2 + 3) to (+ 2 3)
(second a-list)
(first a-list)
(last a-list))
And we say the above thing is a macro named calculate
which take a single argument called a-list
as input:
(defmacro calculate [a-list]
(list ; convert (2 + 3) to (+ 2 3)
(second a-list)
(first a-list)
(last a-list)))
Now one can try this code:
;; macro.clj
(defmacro calculate [a-list]
(list ; convert (2 + 3) to (+ 2 3)
(second a-list)
(first a-list)
(last a-list)))
(println
(calculate (2 + 3)))
This will give 5 as output.
You can also use macroexpand
keyword to expand a macro, for example the code below:
(println
(macroexpand
'(calculate (2 + 3))))
Will print out:
(+ 2 3)
Thats what macro calculate
is supposed to do after you give (2 + 3)
as input.
The entire macro.clj
code is listed below:
;; macro.clj
(defmacro calculate [a-list]
(list ; convert (2 + 3) to (+ 2 3)
(second a-list)
(first a-list)
(last a-list)))
(println
(calculate (2 + 3)))
(println
(macroexpand
'(calculate (2 + 3))))
Run it and you should get output like this:
5
(+ 2 3)
References