Automatically Binding Gensyms

One of the most common macros that almost everyone keeps in their utilities file is with-gensyms. With-gensyms is a macro that binds a list of variables to gensyms. Thats it! All with-gensyms does it take a list of symbols and generates code which binds each of those symbols to a gensym. Although with-gensyms is simple, it removes a lot of boiler plate code. Here is a simple implementation of with-gensyms:

(defmacro with-gensyms (vars &body body)
  <code>(let ,(loop for v in vars collect </code>(,v (gensym)))
     ,@body))

Looking at my implementation of accum, here is how one could simplify it by using with-gensyms. Pay attention to how much boiler plate is removed.

(defmacro accum (accfn &amp;body body)
  (with-gensyms (ghead gtail garg)
    <code>(let* ((,ghead (list nil))
            (,gtail ,ghead))
       (macrolet ((,accfn (,garg)
                    </code>(setf ,',gtail
                           (setf (cdr ,',gtail)
                                 (list ,,garg)))))
         ,@body
         (cdr ,ghead)))))

By removing so much boiler plate, with-gensyms helps greatly reduce the cognitive load in certain cases. This will be important when I introduce once-only, the next macro I plan to talk about. There are also other variations of with-gensyms such as the one in Alexandria which makes it easier to have base names associated with the gensyms created.

Leave a Reply

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