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. That’s 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) `(let ,(loop for v in vars collect `(,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 &body body) (with-gensyms (ghead gtail garg) `(let* ((,ghead (list nil)) (,gtail ,ghead)) (macrolet ((,accfn (,garg) `(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.