Macro system

Pascal Costanza pc at p-cos.net
Sat Nov 24 16:10:23 UTC 2018


Hi,

> On 24 Nov 2018, at 15:14, Alexandre Rademaker <arademaker at gmail.com> wrote:
> 
> 
> In the LoL book we learn the flexibility of the Common Lisp macro system. Reading now 
> 
> http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html <http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html>
> 
> It seems that the Racket macros do not necessarily impose constraints to the programmers. But I never really used it. Does anyone here have experiences with both approaches, sufficient to give insights about the good and bad of each one? 


syntax-case is, strictly speaking, strictly more expressive than Common Lisp macros. If it is worth it to switch to syntax-case because of this, is a different question though, because you can make an argument that the increase in expressiveness doesn’t solve an essential problem.

syntax-case solves a particular case of macro hygiene issues. (syntax-rules solves it too, but removes a lot of other possibilities to express things, whereas syntax-case doesn’t have such restrictions.)

The problem can be illustrated with a simple example:

(defun foo ()
   (let ((x 42))
      (macrolet ((bar () ‘x))
         (let ((x 4711))
            (bar)))))

It can be argued, especially if you’re a very strong believer that everything should be lexically scoped without exception, that (foo) should return 42, because the bar macro apparently refers to the variable named x bound to 42. Alas, (foo) actually returns 4711, and Common Lisp provides no way to solve this /in the language/. (That last part, “in the language”, is very important when speaking of expressiveness. There are very good pragmatic solutions to this issue which, however, only work by convention and are not based on explicit language mechanisms. My favorite solution is to just use different names for the different bindings. ;)

With syntax-case and its default notations, which look very different from the Common Lisp macro system, (foo) would by default return 42, but there are mechanisms in syntax-case to also return 4711 if you explicitly ask for it, without renaming any of the variables.

There is a very interesting paper by Daniel Friedman called “Object-Oriented Style” - see https://www.cs.indiana.edu/~dfried/ <https://www.cs.indiana.edu/~dfried/> - where he implements an object system completely in syntax-case (that is, without the need for any particular runtime support), and where a variant of this issue pops up. I found it very enlightening to try to reimplement this with Common Lisp’s macro system, because you can actually get very far with it. (There are some tricks using &env-based environment objects, macroexpand with explicit passing of such environment objects, and symbol-macrolet, but you will ultimately arrive at a stumbling block where this doesn’t work anymore.)

This paper motivated me to actually embed hygienic macros in Common Lisp. This is described in http://www.jucs.org/jucs_16_2/embedding_hygiene_compatible_macros <http://www.jucs.org/jucs_16_2/embedding_hygiene_compatible_macros>

However, this is not a solution “in the language” because this only works reliably if you write your whole programs in that system.

I’m still not convinced that hygienic macro systems like syntax-case are worth the complexity. Again, just don’t reuse variable names, and you should be fine. (For global variables, it’s easy to use the Common Lisp package system to solve hygiene issues.)

Just my 0.02€.


Pascal

--
Pascal Costanza


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/pro/attachments/20181124/35c6d31e/attachment.html>


More information about the pro mailing list