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

From: Nick Main (david.nick.main at gmail.com)
Date: Tue Aug 6 18:05:09 EDT 2013

By the way, I found that this also works - applying the lexical context of
the dog-unit syntax-object to the dog^ identifier:

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

Again, many thanks.


On Tue, Aug 6, 2013 at 2:32 PM, Carl Eastlund <cce at ccs.neu.edu> wrote:

> 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/638d32b1/attachment.html>

Posted on the users mailing list.