September 16, 2007 at 19:59 Tags Lisp

defmacro

syntax-rules

defmacro

(defmacro do-primes ((var start end) &body; body) `(do ((,var (next-prime ,start) (next-prime (1+ ,var))) (ending-value ,end)) ((> ,var ending-value)) ,@body))

ending-value

(do-primes (ending-value 0 10) (print ending-value))

ending-value

do-primes

(defmacro do-primes ((var start end) &body; body) (let ((ending-value-name (gensym))) `(do ((,var (next-prime ,start) (next-prime (1+ ,var))) (,ending-value-name ,end)) ((> ,var ,ending-value-name)) ,@body)))

I'm in the process of trying to decide which language is better for me - Common Lisp and Scheme. One of the crucial points to take into account is macros, since I personally consider macros to be the most salient feature of Lisp which sets it apart from other languages. The choice is far from simple, of course. On one hand, CL's macros are conceptually much simpler than Scheme's. Whileis pure CL code with the difference that it gets executed at compile-time, Scheme'sis a specialized sub-language which is almost-but-not-quite Scheme. Therefore, it loses the convenient equivalence to normal Scheme code and is, at least for me, much harder to understand and much less intuitive to use. On the other hand, CL'ssuffers from the lack of macro hygiene , as opposed to Scheme's macro system. Simple examples of this symptom are easy to fix. Consider this macro (from Practical Common Lisp ) - iterating over prime numbers in a given range:The problem here is with. This code is broken:Becauseis being re-binded inside. Fortunately, this case is easy to fix:

However, there are cases that can't be fixed in any simple way. For example, look at the last code sample again - what if do-primes is called inside some context where do is redefined to be a different function (with flet or labels ). Sure, this is a far fetched example - but it can happen, and the code will surely break. Think about it - the macro can be used successfully for years, until it gets use in a slightly weird piece of code - and then it will fail in a mysterious way which is quite difficult to debug.

Another far-fetched-but-can-happen problem: if a macro refers to some global symbol and is called inside a lexical context that shadows this symbol. Another hard-to-fix problem.

There are probably other examples of where defmacro can break. Sure, with a judicious use of gensym s and solid coding conventions the probability of something happening is low, and indeed, tons of CL code with macros work perfectly. However, there's this nagging feeling of a looming disaster that may strike at some unknown time with a slightly non-standard piece of code. This isn't pleasant.

Scheme's macro system is hygienic and doesn't suffer from these problems. Of course, this comes at the price of simplicity and ease-of-use, as I mentioned earlier.