Hi,
> On 24 Nov 2018, at 15:14, Alexandre Rademaker <[email protected]> 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