Another beauty of Lisp is its macro facility. I’ve not seen its like in any other language. Because the forms of code and data are equivalent, Lisps macro are not just text substitution, they allow you to modify code structure at compile-time. It’s like having a compiler construction kit as part of the core language, using types and routines identical to what you use in the runtime environment. Compare this to a language like C , where, despite the power of its template meta-language, it employs such a radically different set of tools from the core language that even seasoned C programmers often have little hope of understanding it.
But why is all this necessary? Why do I need to be able to perform compile-time substitutions with a macro, when I can do the same things at runtime with a function? It comes down to evaluation: Before a function is called in Lisp, each of its arguments must be evaluated to yield a concrete value. In fact, it requires that they be evaluated in order1 before the function is ever called.
Say I wanted to write a function called doif, which evaluates its second argument only if the first argument evaluates to true. In Lisp this requires a macro, because an ordinary function call would evaluate that argument in either case:
(defun doif (x y) (if x y)) ; WRONG: both x and y have been evaluated already
(defmacro doif (x y) `(if ,x ,y)) ; Right: y is only evaluated if x is true