Log in

No account? Create an account

How I Know I Don't Know Enough About Lisp Macros

Last night, I posted a long article on my website about How I Know I Don't Know Enough About Lisp Macros. For those who are unfamiliar with Lisp macros, you might enjoy reading the article. I spend a good deal of setup time talking about how Lisp macros kick the pants off of anything else you've heard called a macro before. For here, I will just excerpt the relevant bits for those already familiar with Lisp macros in hopes that you might give me guidance.

In the article, the main example that I work with is assuming that you want to think about your code in terms of jump tables, but you don't necessarily want to write a separate function for each item in the table. You might write some macro like this:

(defmacro do-jump-table ( choice &rest options )
  `(case ,choice
     ,@(loop for ii from 0
            for oo in options
            collecting (list ii oo))
     (otherwise (do-something-graceful))))

Then, you could use it something like this:

(do-jump-table op-code
               (write "NOOP")
               (write "SYNC")
               (when (>= +protocol-version+ 1)
                 (write "QUIT")))

Which would expand to:

(case op-code
  (0 (write "NOOP"))
  (1 (write "SYNC"))
  (2 (when (>= +protocol-version+ 1)
       (write "QUIT")))
  (otherwise (do-something-graceful)))

The do-jump-table macro we just defined expands to one statement (one lisp form): (CASE ...). There are many times when I want my macro to expand to more than one form, however. This isn't legit. I still end up wanting to do it. For example, I might think that since I'm doing things with macros, that I might want the whole (CASE ...) construct to be in the main code and just have the macro expand the different cases:

(case op-code
    (do-jump-table-cases (write "NOOP")
                         (write "SYNC")
                         (when (>= +protocol-version+ 1)
                             (write "QUIT")))
    (otherwise (do-something-especially-graceful)))

Lisp says no. I can understand why it says that. In this case, it's easy enough to work around. But, in other cases, I end up flailing.

I feel that once I understand Lisp macros more completely, I won't keep trying to jam that gorgeous, round peg into all of these square holes in my logic. Anyone have any guidance here?