tidy up the output of lisp macros

For some reason it makes my teeth hurt to have my macros generate code that I wouldn’t have written by hand.  For example it’s not hard to get code like this out of a macro expansion.

(let ()
  (progn
    (if (fp x)
      (progn 
         (f1 x)
         (f2 x)))))

v.s. what I might like:

(when (fp x)
   (f1 x)
   (f2 x))

I probably ought to just relax and ignore it, but instead I often revise macros so the code they generate is nicer to look at.   So that:

`(let ,vars ,@body)

becomes

(if vars
    `(let ,vars ,@body)
    `(progn ,@body))

This is silly!   Now I have ugly macros instead of ugly output.   I’m just moving the ugly bits around.

So I’ve started doing this:

(tidy-expression `(let ,vars ,@body))

where tidy-expression is something like this:

(defun tidy-expression (x)
  (match x
    (`(or ,a (or ,@b)) `(or ,a ,@b))
    (`(progn ,a (progn ,@b)) `(progn ,a ,@b))
    (`(progn ,x) x)
    (`(and ,a (and ,@b)) `(and ,a ,@b))
    (`(if ,a (progn ,@b)) `(when ,a ,@b))
    (`(if ,a (progn ,@b) (progn ,@c)) `(cond (,a ,@b) (t ,@c)))
    (`(if ,a (progn ,@b) ,c) `(cond (,a ,@b) (t ,c)))
    (`(if ,a ,b (progn ,@c)) `(cond (,a ,b) (t ,@c)))
    (`(let ,vs (progn ,@body)) (tidy-expression `(let ,vs ,@body)))
    (`(let nil ,@body) (tidy-expression `(progn ,@body)))
    (_ x)))

It’s another chapter in my crush on optima.

I write these tidy up functions as necessary.

That example only chews on the top of the form.   If you wanted something to clean up the first example you’d need to write tidy-expression-all.

(tidy-expression-all
 '(progn
   (if (fp x)
       (progn 
         (f1 x)
         (f2 x)))))
-->
(when (fp x) (f1 x) (f2 x))

This all reminds me of Warren Teitelman’s programmer’s assistant in Interlisp.  It reminds me of some of the things that flycheck in Emacs does for other programming languages.   It reminds me that I’ve been wondering what would a lint for Common Lisp would look like.

I bet somebody already wrote a generalized tidy expression and I just don’t know were to look.

2 thoughts on “tidy up the output of lisp macros

  1. Zach Beane

    Riesbeck’s LISP-CRITIC does something like this, but it’s more about hinting about ugliness or weirdness than about directly fixing it.

    Cool stuff!

  2. Andy Fingerhut

    I don’t have any experience with Common Lisp lint tools myself, but you can find several projects from the past with a simple Google search for ‘lisp lint tool’. I have helped enhance a lint tool for the Lisp dialect Clojure recently, called Eastwood (https://github.com/jonase/eastwood), and went looking for existing tools to see what kinds of checking they performed.

Leave a Reply

Your email address will not be published. Required fields are marked *