[racket] Again on bindings visibility in eval

From: Eli Barzilay (eli at barzilay.org)
Date: Thu Jul 14 11:23:18 EDT 2011

Two hours ago, Markku Rontu wrote:
> > this is not really true. The domain specific languages of
> > syntax-rules and syntax-case macro transformers exist purely for
> > your convenience.  You can always manipulate syntax objects
> > directly, all the necessary procedures are available and
> > documented in section 11 of the Racket reference manual.
> >
> I'm sure the section 11 does go through the relevant issues, but
> doesn't feel like a good introduction to the matter.

It's a reference, it's not supposed to be an introduction.  For a more
in-depth introduction than my blog post, see the chapter in the racket
guide:

  http://docs.racket-lang.org/guide/macros.html


> I can theorise that I can manipulate these syntax objects with plain
> old functions but nowhere does it seem to show a complete useful
> case. What I'm missing is an example that contains all the bits but
> that is not as complicated like the Racket sources themselves. Maybe
> I just didn't find it?

Note that usually you start with `syntax-rules' because it's simple
and covers many cases.  But running straight to the macro system
bowels can be confusing since it's not just "lists and symbols".  So
the main tool that is used is `syntax-case', which can be used in a
very similar way to `syntax-rules':

  (define def
    (syntax-rules (=)
      [(def x = y) (define x y)]))

gets translated to

  (define (def stx)
    (syntax-case stx (=)
      [(def x = y) #'(define x y)]))

It looks similar, but there are important differences:

* `syntax-rules' is creating a macro function (=> it is itself a
  macro) for you, abstracting all of the details out.  The translation
  defines `def' as a function directly -- se we have a name for the
  input syntax, `stx' is often used by convention.

* We then use `syntax-case' which has the same kind of pattern
  language you know from `syntax-rules', but it needs to have its
  input specified directly.  It's common to pass `stx', the input to
  the macro, but you can really give it anything you want.

* And the most important change is that #' in the result.  With
  `syntax-rules', the results are actually templates for plugging
  pattern variables in.  But since we're writing plain racket code
  here, the results can be any racket expression.  In this case, I use
  #'(define x y) which is actually short for (syntax (define x y)).
  This `syntax' thing is very similar to `quote', or actually more
  like a kind of a quasiquote since pattern matched variables are
  plugged into it -- so it's not really `x' and `y' that will be in
  the result, it will instead be what the `x' and `y' variables
  matched over when `stx' was fed into `syntax-case'.

Again, see that blog post for an introduction that explains more from
this POV.

(This kind of explanations were also made countless times; it's easy
to fall into the syntax-rules-only trap though.)


> It's simple, it's been explained countless times, it works in many
> cases.

No, it's broken in pretty much all cases.  Give me a single symbolic
macro and I'll show you how it's broken.  (And point out how CL
bypasses the problem...)

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


Posted on the users mailing list.