↩ go back to index

Releasing Some New Common Lisp Macros

April 8, 2023

Last week or so I finally sat down and wrote my pretty ideal binding macro for Common Lisp—basically a rite of passage for any Lisper given all the other ones I've stumbled across. I just fully rewrote it yesterday after using it in some real code and cleaning it up a bit; so I guess I should actually tell people about it in case anyone ends up interested in it since I really like it so far. Although like almost all of my projects it's written for me and I don't expect anyone else to end up using it (not necessarily a bad thing).

The BIND macro itself can be found at:

https://git.sr.ht/~nytpu/lisp-utils/tree/master/bind.lisp

I decided to bundle it up with a little Design by Contract library that I wrote last year and ended up heavily using in Lasso. It's in an uncreatively named lisp-utils ASDF system:

https://git.sr.ht/~nytpu/lisp-utils

I don't have any specific plans to expand it out further, but I forsee adding more stuff if/when I write some cool general-purpose macro in the course of other programming. At any rate, I'm very firm on making every file/component in it entirely self-contained (including the DEFPACKAGEs) and with zero external dependencies, so you can just copy the file of interest into your project, install the system to your Quicklisp local projects if you use that for dependency management, or otherwise install the system where ASDF can find lisp-utils.asd.

I heavily took inspiration from a few older binding macros, namely Scott L. Burson's new let that was apparently originally written all the way back in 1980 (before Common Lisp existed!), and Ron Garret's BINDING-BLOCK, Ron Garrent being the author of the nice Lisping at JPL article. I figured taking ideas from some very experienced and intelligent Lisp programmers, and then just morphing them into a syntax I like would be a good strategy. I think I succesfully captured the flattening of deeply-nested bindings of BINDING-BLOCK (especially with my heavy use of multiple return values which otherwise gets super nested), while still keeping it less procedural and more LET-style like new let.

After using it in some real code that I'm working on, it confirmed my thought that most of the time I'd be using it as a drop-in replacement for LET/LET*, so I wanted to make sure that runs of sequential bindings of the same type (currently LET-style bindinds and lambdas) are condensed into one single invocation of LET* or LABELS. This means that using BIND in place of LET* should have zero impact even without a decent optimizing implementation, since it expands into an identical single LET*. Even with more complex statements using the more fancy features, the number of forms is minimised wherever possible to where it should be no worse than writing the equivalent expression by hand. The worst is perhaps some superfluous use of LET* where LET could've been used instead, but a big part of yesterday's rewrite was making the bindings always sequential instead of trying to have a special separate sequential operator that made it annoying and verbose to use.

Overall I'm pretty happy with it so far, and I am still quite fond of that Design by Contract library so I'm glad I extracted it from Lasso into a standalone thing. Maybe check them out if you're interested?