Reputation: 12184
I just started with macros and made a simple one to return maximum number out of a list.
(defmacro macro-max [list] (apply max list))
and If I make a function to do the same, it will be.
(defn macro-max [list] (apply max list))
I am just exploring Clojure, so I don't know much.
I may sound completely silly to experts, But it looks like I can pretty much define a function instead of a macro.
Upvotes: 9
Views: 495
Reputation: 15703
Macros are functions. The difference is only in evaluation time (macros are evaluated at macro expansion time, which is a step in compiling, functions are evaluated at runtime). Also, Macros work on S-Expressions (so macro is a bit like a function where you quote every single argument, i.e. you could easily replace any macro (mac a b)
with a function (fun 'a 'b)
.
Upvotes: 1
Reputation: 45171
If a function can do, then by all means use a function. Clojure libraries follow this rule, so probably most macros defined there cannot really be expressed as functions. Take the ->>
macro:
(->>
"abcdefghij"
(take 5)
(drop 3)
(apply str))
The above evaluates to "de". A function could not do that, since the arguments of the macro do not make sense when evaluated by themselves - (take 5)
raises an error when evaluated.
What the macro does is modify the forms before they are evaluated (by inserting the previous expression as the last argument of the form.) This is what only a macro can do, not a function.
Upvotes: 1
Reputation: 2786
I don't have experience with macros but it will allow you extend combilier by your functions. I am not sure but it is evaluated at runtime.
Upvotes: -7
Reputation: 5629
The difference comes to life when you don't want to evaluate your arguments unless needed.
Consider this example:
(defn unless [pred body]
(when (not pred)
body))
This doesn't work since arguments to a function are eagerly evaluated. So body always runs, as shown below:
(unless (zero? 2)
(prn "Not zero!"))
;; "Not zero!"
(unless (zero? 0)
(prn "Not zero!"))
;; "Not zero!"
Both executions above print "Not zero!", which is clearly wrong.
The only way to write our unless
utility is by using a macro:
(defmacro unless [pred body]
`(when (not ~pred)
~@body))
Now if we give it a try, we'll see it works as expected:
(unless (zero? 2)
(prn "Not zero!"))
;; "Not zero!"
(unless (zero? 0)
(prn "Not zero!"))
;; this prints nothing
Macros only evaluate its arguments when the developer decides to.
You'll notice some special characters in the macro such as `, ~ and ~@. They stand for syntax-quote, unquote and unquote-splicing, respectively and are explained here.
I suggest you study these symbols.
Hope this helps.
Upvotes: 9