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