[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: problems with with-syntax



Quoting Doug Orleans:
> I'm trying to make a macro that does some computation at expansion
> time.  I defined a helper function at the top level, but when I call
> it in a binding clause in with-syntax, MzScheme says it's undefined.
> Here's a boiled-down version of the code:
> 
>   (define (id x) x)
> 
>   (define-syntax (foobar x)
>     (syntax-case x ()
>       ((_ expr)
>        (with-syntax ((q (id (syntax expr))))
> 	 (syntax q)))))
> 
>   > (foobar 2)
>   reference to undefined identifier: id
> 
> What environment is the "stx-expr" part of a with-syntax construct
> evaluated in?  What's a better way to write this sort of thing?

There are two parallel enviornments: a "normal" environment and a
transformer environment. Top-level definitions are visible in the
normal environment, and `require' also extends the normal environment.
The only way to extend the transformer is with `require-for-syntax'.

So, the above example can be re-written

  (module m mzscheme
    (provide id)
    (define (id x) x))

  (require-for-syntax m)

  (define-syntax (foobar x)
    (syntax-case x ()
      ((_ expr)
       (with-syntax ((q (id (syntax expr))))
	 (syntax q)))))

It would be better to put `foobar' in its own module and avoid the top
level entirely, though.


Splitting the environment allows compilers, syntax checkers, etc. to
see how much of the code needs to be evaluated at compile-time. For
example, imagine trying to run "Check Syntax" on the original code
(cinluding the use of `foobar'); the checker wouldn't know that it
needs to execute the `id' definition, instead of simply checking it. In
contrast, the `require-for-syntax' in the second program tells the
checker exactly which code that needs to be executed.

Matthew