[plt-scheme] Macro expanding into define-values/invoke-unit?
Anthony Cowley wrote:
> How can I get a macro to expand into a (define-values/invoke-unit ...)
> form? That is, I have a macro that constructs syntax that looks
> correct, but is left unexpanded before the rest of the module
> containing my macro invocation is expanded. I think the below
> demonstrates the issue. When run, the module produces the value 9, but
> if the "Works!" line is commented out, while the following line is
> uncommented, then "bar" is an unbound identifier. In my case, my macro
> lives in another module, so if there are some phase gymnastics needed,
> that would be fine, but I haven't been able to discover them yet.
It's not a phase problem. Those usually manifest as unbound identifier
errors.
'define-values/invoke-unit' is an unhygienic binding form; it extracts
the names to bind from the signature(s) in the 'export' clause. All
unhygienic binding forms must decide what lexical context to apply to
the names they bind. For example, 'define-struct' uses the lexical
context of the identifier given for the struct name.
'define-values/invoke-unit' seems to use the lexical context from the
identifier given as the name of the signature to export. In your case,
'foo^'. Since that's introduced by the 'mkfoo' macro, the binding of
'bar' is also considered "introduced" (it inherits a mark from 'foo^'),
which makes it inaccessible to you at the repl.
Here's a version of 'mkfoo' that probably works:
(define-syntax (mkfoo stx)
(syntax-case stx ()
[(_ x)
(with-syntax ([foo^ (syntax-local-introduce #'foo^)])
#'(define-values/invoke-unit x (import) (export foo^)))]))
The use of 'syntax-local-introduce' cancels the mark on 'foo^'.
A better solution, I think, would be to change
'define-values/invoke-unit' et al to accept an explicit lexical context
argument.
Ryan