tags:

views:

292

answers:

5

What is the difference between the defn and defmacro ? What is the difference between a function and a macro ?

A: 

defn define a function, and defmacro define a macro.
Macro is like a function but treat it's argument (if they are expressions as data), then process them and return data (list of symbols which are the code) and then evaluate that return code. So it's replace one code with another (on compile time).

jcubic
+11  A: 

defn defines a function, defmacro defines a macro.

The difference between functions and macros is that on a function call first the arguments of the function are evaluated then the body of the function is evaluated using the arguments.

Macros on the other hand describe a transformation from one piece of code to another. Any evaluation takes place after the transformation.

This means that arguments may be evaluated multiple times or not at all. As an example or is a macro. If the first argument of or is false, the second argument will never be evaluated. If or were a function, this would not be possible, because the arguments would always be evaluated before the function runs.

Another consequence of this is that the arguments of a macro need not be a valid expression before the macro is expanded. For example you could define a macro mymacro such that (mymacro (12 23 +)) expands to (+ 23 12), so this will work even though (12 23 +) on its own would be nonsense. You couldn't do that with a function because (12 23 +) would be evaluated, and cause an error, before the function runs.

A small example to illustrate the difference:

(defmacro twice [e] `(do ~e ~e))
(twice (println "foo"))

The macro twice gets the list (println "foo") as an argument. It then transforms it into the list (do (println "foo") (println "foo")). This new code is what gets executed.

(defn twice [e] `(do ~e ~e))
(twice (println "foo"))

Here println "foo" is evaluted right away. Since println returns nil, twice is called with nil as its argument. twice now produces the list (do nil nil) and returns that as its result. Note that here (do nil nil) is not evaluated as code, it's just treated as a list.

sepp2k
what do you mean by "arguments may be evaluated multiple times" when referring to macros ? can you give an example or explain more ?
Belun
I don't think anybody would do this, but imagine a forloop macro. You might invoke it as (forloop [x 0] (< x 10) (+ x 1) (print x)). The clauses (< x 10), (+ x 1), and (print x) would not get evaluated up front, but would get evaluated for every iteration of the loop. For that reason, this could only be implemented as a macro. A function would evaluate its arguments greedily. Macros are one way to achieve laziness in Clojure.
Daniel Yankowsky
@Belun: Most simple example: (defmacro twice [e] `(do ~e ~e)) (twice (println "foo")) will print foo twice.
sepp2k
Cheers sepp2k, your answer is above and beyond my descriptive abilities! +1
sleepynate
I think this explanation miss an important point. The first difference between macro and function is the time of their evaluation. A macro is evaluated at compile-time, a function is called at runtime. All the other differences come from that difference.
Nicolas Oury
@Nicolas: I don't agree (about everything else following from that, I mean). Non-recursive functions called with constant arguments, are also often evaluated at compile-time as an optimization, but they still don't have any of the properties that macros have. Also it's perfectly possible to write an implementation of clojure that is entirely interpreted (and thus would have no compile-time) and which would still behave exactly like the official clojure implementation. I.e. macro expansion happening at compile-time is an implementation detail.
sepp2k
+2  A: 

Without sounding snarky, one creates a function, while the other creates a macro. In Common Lisp (and I'll assume this applies to clojure as well), Macros are expanded before actual compilation of functions. So, lazy-cat:

(defmacro lazy-cat
  "Expands to code which yields a lazy sequence of the concatenation
  of the supplied colls. Each coll expr is not evaluated until it is
  needed.

  (lazy-cat xs ys zs) === (concat (lazy-seq xs) (lazy-seq ys) (lazy-seq zs))"
  {:added "1.0"}
  [& colls]
  `(concat ~@(map #(list `lazy-seq %) colls)))

Will actually be expanded to

`(concat ~@(map #(list `lazy-seq %) colls)))

of which lazy-seq will then be further expanded to

(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))

all before the actually processing of the data passed to them.

There's a very cute story that helps explain the difference (followed by some informative examples) at Practical Common Lisp: Chapter 8

sleepynate
+4  A: 

A macro is like having an apprentice programmer that you can write notes to:

Sometimes, if I'm trying to debug something, I like to change something like

(* 3 2)

Into something like this:

(let [a (* 3 2)] (println "dbg: (* 3 2) = " a) a)

Which works the same way, except that it prints out the expression it has just evaluated, and its value, as well as returning the value as the result of the whole expression. This means that I can leave my code undisturbed whilst examining intermediate values.

This can be very useful, but it's time consuming and error prone to type. You might imagine delegating such tasks to your apprentice!

Rather than hiring an apprentice, you can program the compiler to do these things for you.

;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))

Now try:

(* 4 (dbg (* 3 2)))

It actually makes the textual transformation on the code for you, although being a computer, it chooses unreadable names for its variables instead of the "a" I would have chosen.

We can ask it what it would do for a given expression:

(macroexpand '(dbg (* 3 2)))

And this is its answer, so you can see that it really is rewriting the code for you:

(let* [x__1698__auto__ (* 3 2)]
      (clojure.core/println "dbg:" (quote (* 3 2)) "=" x__1698__auto__)
      x__1698__auto__)

Try to write a function dbgf that does the same thing, and you'll have problems, because (dbgf (* 3 2)) -> (dbgf 6) before dbgf is called, and so whatever dbgf does, it can't recover the expression that it needs to print out.

I'm sure you can think of many ways round this, like run-time evaluation or passing in a string. Try to write dbg using defn instead of defmacro. It will be a good way to convince yourself that macros are good things to have in a language. Once you've got it working, try using it on an expression that has a side effect as well as a value, like

(dbg (print "hi"))

In fact macros are so good to have that we're prepared to live with the (brackety ((syntax))) of LISPs in order to get them. (Although I must say that I rather like it for its own sake (but then (I am) a bit weird (in the head)).

C also has macros, which work in roughly the same way, but they're always going wrong, and to get them right you need to put so many brackets into your program that it looks like LISP!

You're actually recommended not to use C's macros because they're so error prone, although I have seen them used to great effect by people who really knew what they were doing.

LISP macros are so effective that the language itself is built out of them, as you'll notice if you look at the Clojure source files that are themselves written in Clojure.

The base language is very simple so that it's easy to implement, and then the complex superstructure is built up using macros.

I do hope this helps. It's rather longer than my usual answers, because you've asked a deep question. Good luck.

John Lawrence Aspden
C macros are _not_ like Lisp macros. C macros operate on the _text_, i.e. on the string of characters making up your source code, while Lisp macros operate on the _abstract syntax tree_, i.e. the program structure.
Svante
Good point, thanks. Added the word 'roughly'.
John Lawrence Aspden
your example code is a bit to much for a newbie. try explaining the extra stuff in your examples : x#, ~x, '~x. try explaining your way of thinking that got you to the solution, this way a newbie like me can get you :)
Belun
I will try to. It will take me a while. I'll post a link here when it's done.
John Lawrence Aspden
I ended up writing a bit of a series!: http://learnclojure.blogspot.com/2010/09/defn-vs-defmacro-what-is-macro-why-is.html, http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-i-getting.html, http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html, http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
John Lawrence Aspden
+3  A: 

The Other answers cover this well in depth so I'll try to cover it as succinctly as I can. I would appreciate edits/comments on how to write it more succinctly while keeping it clear:

  • a function transforms values into other values.
    (reduce + (map inc [1 2 3])) => 9

  • a macro transforms code into other code.
    (-> x a b c) => (c (b (a x))))

Arthur Ulfeldt
the first example is too simple, the second example is too complicated :D
Belun
ok, made the first one more complicated to balance things out.. :)
Arthur Ulfeldt
and made the macro example simpler
Arthur Ulfeldt