I am attempting to answer the following exercise.
Write a macro function OUR-IF that translates the following macro calls.
(our-if a then b) translates to (cond (a b)) (our-if a then b else c) translates to (cond (a b) (t c))
My solution is the following:
(defmacro our-if (test then then-clause &optional else else-clause)
(if (equal 'else else)
`(cond (,test ,then-clause) (t ,else-clause))
`(cond (,test ,then-clause))))
That works fine, but I'm not totally satisfied by it. There's no syntax checking on the "then" and "else" arguments. Then could be anything. And if I gave the wrong symbol for "else", I'd get the wrong behaviour. The symbols aren't even checked to be symbols.
I could model them as keyword arguments and get close, but that's not exactly right either. It reminds me of the LOOP macro, which is a much more complicated example of the same thing. That made me wonder: how does LOOP do it? Maybe there's some pattern for "mini languages in macro arguments". But I couldn't find anything.
I found the hyperspec page for LOOP which confirms that the grammar is complicated. But I don't know if there's a nice way to implement it.
This is what pattern matching is for. There are a bunch of CL pattern matchers, dsm is one I am familar with which was designed for dealing with macros, albeit not quite this sort of 'let's just splice in some fortran' macro.
Using dsm in
defmacro:Or if you use the
define-matching-macroform it includes as an example:It may be that other matchers are better for the case where there are lots of literals, as here.
In the case of
loopthe syntax keywords are compared by name, not symbol equality. Although it is definitely overkill in this simple case, you can do this pretty easily using spam:This is pretty seriously over-the-top for this simple case, but for more general things it can help.