[racket] Again on bindings visibility in eval

From: Eli Barzilay (eli at barzilay.org)
Date: Thu Jul 14 14:58:25 EDT 2011

25 minutes ago, Markku Rontu wrote:
> > > http://hipster.home.xs4all.nl/lib/scheme/gauche/define-syntax-primer.txt
> [...]
> 
> Still, I count it as good eye opening material :)

Well, it has a heavy focus on "computations via rewriting", which can
of course be an eye opener, but off-topic when talking about practical
macro writing.  (It still is practical, if you're confined to R5RS for
portability, but we're now in a racket context.)


> Granted your cited blog post is good too but it's not a complete
> tutorial.

It's inteneded as a quick thing for people who are familiar with
symbolic `defmacro' things.


> > If you're working in Racket, it makes much more sense to really use
> > its syntax system rather than stick to those tricks.
> >
> However, I find syntax-case to be very similar if you proceed to it
> as next step from syntax-rules. I mean that if you take it as an
> improved syntax-rules, you will likely end up using it just like
> syntax-rules except for the part about breaking hygiene. This is
> just my experience.

Not at all.  The main addition is exactly what you complained about:
having the full language.  Here's an implementation of a function
application with reversed arguments, with `syntax-rules':

  (define-syntax rapp
    (syntax-rules ()
      [(rapp f x ...) (rapp* f (x ...))]))
  (define-syntax rapp*
    (syntax-rules ()
      [(rapp* f (x0 x ...) r ...) (rapp* f (x ...) x0 r ...)]
      [(rapp* f () r ...) (f r ...)]))

Can you see the reversal?  It's of course possible -- and even an
instance of such eye openning, but I really wouldn't call that
obvious.  (And un-obvious is bad -- it leads to surprising bugs.)

Here is the same using `syntax-case':

  (define-syntax (rapp stx)
    (syntax-case stx ()
      [(rapp f x ...) #`(f #,@(reverse (syntax->list #'(x ...))))]))

and now the reversal is explicit -- it says "reverse"...

There's of course the naive translation of `syntax-rules' to
`syntax-case', leading to the same bad code as the first example.
That's why the first thing that should be made obvious is that there
is no magic here -- these are just plain values.  Once *that* is
clear, it should also be clear that such a translation is a bad idea.

As an antidote to such illusions of black magic, here's another
version that doesn't even use `syntax-case':

  (define-syntax (rapp stx)
    (let ([l (cdr (syntax->list stx))])
      (datum->syntax stx (cons (car l) (reverse (cdr l))))))


> > Read that blog post: it shows you how you can use plain racket
> > code to write macros -- and it introduces some of the tools that
> > make it easy to deal with syntax values.
> 
> I think what is mainly missing is a bit more positive publicity in
> this area. A great collection of tools for writing macros exists,
> and obviously great things are being written using them (TR
> etc.). Just need to produce enough material so that the search
> engines start to find the good stuff.

That is a social problem:
- There are many people who still think that macros are a bad idea in
  general, and advocate that idea.
- From the peole who manage to get passed that propaganda line, there
  are people who think that there's nothing wrong with plain CPP-style
  textual macros, and advocate that idea.
- From the peole who manage to get passed that propaganda line, there
  are people who think that symbolic macros are superior, and advocate
  that idea.
- From the peole who manage to get passed that propaganda line, there
  are people who think that `syntax-rules' are better since they don't
  get phases, and advocate that idea.

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


Posted on the users mailing list.