[racket] define-values/invoke-unit not working when generated by a macro
The concept is pretty opaque; syntax object contexts are a fairly tricky,
black-magic part of the language. There is a rhyme and reason to them, but
it isn't terribly high level or user-friendly. Sadly, no one yet knows how
to do better for macros as powerful as Racket's. I've spent a long time
with them, and I got the deepest understanding from reading Kent Dybvig's
paper "Syntactic Abstraction in Scheme" over and over. And eventually
implementing it myself, which was incidental but certainly made things
crystal clear. I don't know that it's necessary to go that far to work
with advanced macros; mostly, writing things with default hygiene as much
as possible, and occasionally using syntax-local-introduce for tricky stuff
like macros that produce units or require forms, will get you pretty far.
Carl Eastlund
On Tue, Aug 6, 2013 at 5:57 PM, Nick Main <david.nick.main at gmail.com> wrote:
> Many thanks !
>
> The problem makes sense and the solution works.
>
> Are there any explanations of "syntax marks" beyond those in the "Syntax
> Model" section of the documentation ? The concept seems opaque.
>
>
> 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/bb962a91/attachment-0001.html>