[racket] define-syntax comment
On 03/06/2014 06:15 PM, Jon Stenerson wrote:
> When I run this in DrRacket, the first (m) gives 0 and the second gives
> #<procedure:+>.
>
> #lang racket
> (m)
> (define-syntax m (lambda (stx) #'+))
> (m)
>
> Seems a little strange to me. I see why it happens but I guess I had
> expected a "use before definition" warning.
This one's fun! I know you know why it happens, but to explain to others:
The first (m) expands to (#%app m). The `m' isn't expanded because it's
not defined as a syntax transformer yet. But it isn't transformed into
(#%top . m) because `m' is bound in the body of the module.
Then (define-syntax m ...) is expanded. Then (m), which expands to #'+.
Now that all the module-level expressions are expanded, the expander
starts on their subexpressions, so the first `m' within (m) on line 2 is
expanded, and is of course transformed to #'+. The program ends up
(+)
(define-syntax m ...)
+
with each non-definition wrapped in a `print-values', so of course the
values 0 and + are printed. Neet.
The way to deal with it is write the syntax transformer so it
pattern-matches on how it's called (as the head of a larger expression
or not) and expands appropriately:
#lang racket
(m)
(define-syntax (m stx)
(syntax-case stx ()
[(_ . es) (syntax/loc stx (+ . es))]))
(m)
This raises a syntax error on the first (m) because the inner `m' fails
to match.
I don't know whether there's any sensible warning Racket can give for
the original macro. I'll let the workers of deeper black magic answer
that one.
Neil ⊥