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

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Tue Aug 6 18:13:40 EDT 2013

That's not a good solution.  It works in your current example, but there
will be many possible cases where it won't.  You're asking the macro system
to use whatever is currently bound to the name "dog^" in the context the
user wants to bind a name.  That won't always be the dog^ interface, if
your macro is used somewhere that the interface is not in scope, or is
bound to a different name.  For instance, it won't work if you import
macros.rkt using prefix-in.

Carl Eastlund


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

> 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/0020f3ee/attachment.html>

Posted on the users mailing list.