[racket] Again on bindings visibility in eval
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!