[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: need help with syntax-case/syntax/datum->syntax-object
Quoting Doug Orleans:
> My (shaky) understanding of syntax-case makes me believe this should
> instead be:
>
> (lambda (stx)
> (syntax-case stx (literal-identifier ···)
> ((generated-identifier . pattern) (syntax template))
> ···))
Yep - thanks.
> Okay, here's what I'm trying to do [...]
Condensed version:
* The macro `lambda-foo' introduces a binding that is supposed to
capture variables introduced at the use-site of `lambda-foo' (i.e.,
it's intentially breaking hygiene).
* The macro `traced-lambda-foo-1' expands to a use of `lambda-foo'.
* The binding introduced by `lambda-foo' via `traced-lambda-foo-1'
doesn't capture variables introduced at the use-site of
`traced-lambda-foo-1'.
Here's the reason: `lambda-foo' does capture variables at the use-site
of `lambda-foo'. But, in the case of `traced-lambda-foo-1', the
use-site is in the implementation of the `traced-lambda-foo-1' macro,
*not* the original use-site of `traced-lambda-foo-1'.
So, it captures the `foo' in `(display foo)' here:
> (define-syntax traced-lambda-foo-1
> (lambda (x)
> (syntax-case x ()
> ((_ body ...)
> (syntax (lambda-foo (display foo) (newline) body ...))))))
but not the `foo' in `(+ foo 1)' here:
> > (define add1 (traced-lambda-foo-1 (+ foo 1)))
> Is there a way to get this to work right?
Not a good one that I've found.
Since `lambda-foo' is trying to discover the original context through
the leading keyword at the use-site, you could do something like this:
(define-syntax traced-lambda-foo-3
(lambda (x)
(syntax-case x ()
((_ body ...)
(with-syntax ((lambda-foo (datum->syntax-object (syntax _)
'lambda-foo))
(foo (datum->syntax-object (syntax _) 'foo)))
(syntax (lambda-foo (display foo) (newline) body ...)))))))
but `traced-lambda-foo-3' will only work in a context where
`lambda-foo' is also bound. That may be good enough for your puposes,
but it's not a nice solution in general.
In general, the only way I know to avoid the problem is to avoid macros
that expand into uses of hygiene-breaking macros. For example,
`class-100' expands to `class*/names' (hygienic) instead of `class'
(which introduces non-hygienic `this', `super-instantiate', and
`super-make-object' bindings).
> Why does it seem to do the right thing when expanded incrementally,
> but not when it's expanded all at once?
Unfortunately, `expand' is not the fixpoint of `expand-once'. (I see
that the documentation neglects to mention that important fact. Oops!)
As far as I can tell, the underlying expansion mechanism isn't actually
compatible with `expand-once'. To make it almost work --- usually
enough for debugging --- MzScheme's `expand-once' loses a bit of "mark"
information, which traces the introduction of variables by macros. It's
exactly that loss that makes `traced-lambda-foo-1' work piecewise.
[BTW, multiple calls to `expand' do work reliably, without flattening
the syntax to an S-expression, thanks to the way that "mark"
information is lost.]
Matthew