[plt-scheme] Let-syntax not transparent to top-level defines

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Aug 22 22:24:55 EDT 2002

At Thu, 22 Aug 2002 17:54:46 -0400, Brian Campbell wrote:
> I am writing a macro that expands to a let-syntax expression, 
> which binds #%app. This works fine when it's wrapped around most 
> expressions. When you wrap it around a group of top level 
> defines, however, it introduces a new lexical scope, rather than 
> being transparent to them. I would like to have something like 
> the following at the top level:
> (with-tracing
>    (define (foo bar)
>      (+ 1 bar))
>    (define (baz quux)
>      (* 10 quux)))
> and have those defines apply at the top level with #%app rebound 
> to the right thing. I also need this to work within the top 
> level of a module. Is there any way for me to do something like 
> this?

I'm a little confused about the setup. `(with-tracing (+ 1 2))'
presumably doesn't expand to `(let-syntax ([#%app ...]) (+ 1 2))'. The
`#%app' binding wouldn't affect the `(+ 1 2)' part, since the binding
is introduced by the macro, right? Maybe you're using
`fluid-let-syntax'? Or maybe something else is going on and the details
don't matter.

for some information on why `let-syntax' and `fluid-let-syntax'
introduce a new scope.

I actually don't know how to solve the problem if a `define-syntax'
expression can appear inside `with-tracing'. Otherwise, probably it can
be solved using the very machinery that forces `let-syntax' to create
new scopes.

The idea is to push the `let-syntax' into the body of a definition. To
do that, use `local-expand' to partially expand each body expression
within `with-tracing', something like this:

     (kernel-form-identifier-list (quote-syntax here)))

where `kernel-form-identifier-list' comes from "kerncase.ss" in the
"syntax" collection. The result of `local-expand' will either have the

  (define-values (id ....) expr)


  (define-syntaxes (id ....) expr)

or it will be an non-definition.

 * In the first case, you can move the `let-syntax' inside the

 * In the second case, you're stuck. Pushing `let-syntax' into the
   definition would change its phase.

 * In the other cases, you can wrap the entire [partially expanded]
   expression with `let-syntax'.

And you really only need to do this partial expansion if
`(syntax-local-context)' isn't 'expression.

Long term, I hope the solution to these problems is to eliminate
`local-expand', but we can't do without it right now.

Hope that helps,

Posted on the users mailing list.