[plt-scheme] Macro expanding into define-values/invoke-unit?

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Mon Jul 13 00:54:21 EDT 2009

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


Posted on the users mailing list.