[racket] define-values/invoke-unit not working when generated by a macro

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Tue Aug 6 17:32:00 EDT 2013

Nick,

The unit system has some non-hygienic behavior, by design.  That is, it
introduces names that aren't part of its input, which isn't the default
behavior of hygienic macros.  Of course we want this -- we want the macro
use-dog to bind the names woof and bark, which aren't directly part of its
input.  But getting the context right, and still "playing nice" with other
hygienic macros, is slightly tricky.

So in this context, what's the trick?  The names bound by
define-values/invoke-unit are bound in the context that the interface names
are written in.  Note that the interface names in use-dog are written
inside the macro definition.  The macro system assumes anything from inside
a macro is a local or "temporary" name that should be hidden from the rest
of the program.  You can fix this with the syntax-local-introduce function,
which (basically) toggles the context of a given syntax object between the
current macro expansion step and its call site.

So right now you are getting two definitions each for woof and bark, one
visible by the main module and one only visible from the expansion of the
use-dog macro.  If you call use-dog multiple times, you'll get more,
separate, unique contexts.

You can fix it like this, to make use-dog bind things in the context where
it is called:

    (define-syntax (use-dog stx)
      (syntax-case stx ()
        ([_ dog-unit]
         #`(define-values/invoke-unit dog-unit
             (import)
             (export #,(syntax-local-introduce #'dog^))))))

Carl Eastlund

On Tue, Aug 6, 2013 at 5:11 PM, Nick Main <david.nick.main at gmail.com> wrote:

> I am attempting to write a macro to clean up the use
> of define-values/invoke-unit and finding some confusing behavior.
>
>  My macros module is:
>
> #lang racket
> (provide (all-defined-out))
>
> (define-signature dog^
>   (woof
>    bark))
>
> (define mutt@
>   (unit
>     (import)
>     (export dog^)
>     (define (woof) (printf "Wuf !!\n"))
>     (define (bark) (printf "RarRarRar !!\n"))))
>
> (define-syntax use-dog
>   (syntax-rules ()
>     ([_ dog-unit]
>      (define-values/invoke-unit dog-unit
>        (import)
>        (export dog^)))))
>
>
> ..and the module using it is:
>
> #lang racket
> (require "macros.rkt")
>
> (define-values/invoke-unit mutt@
>   (import)
>   (export dog^))
>
>  (use-dog mutt@)
>
> (woof)
>  (woof)
> (bark)
> (woof)
>
>
> I am trying to make the "use-dog" macro expand to the equivalent
> define-values/invoke-unit form as shown.
> If I comment out the define-value/invoke-unit form I get warning about
> unbound identifier woof - implying that the (use-dog dog^) form is not
> doing the job. Moreover, the second module as it stands does not give a
> warning about duplicate definitions for woof or bark (as it does if I
> duplicate the define-values/invoke-unit form) - further indicating the
> non-action of use-dog.
>
> The macro stepper shows use-dog expand exactly as expected, but it then
> seems to be ignored without any warnings.
>
> Is there something I am misunderstanding here, or is this a bug ?
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130806/752462cf/attachment.html>

Posted on the users mailing list.