[racket] macro help redux

From: Todd O'Bryan (toddobryan at gmail.com)
Date: Fri Jun 11 16:23:33 EDT 2010

Thanks for responding. I've been away chaperoning students at camp for
the past three days--thus my belated response.

This is starting to make more sense. I got that there was a difference
between data and syntax, but I thought they were much more fluidly
convertible. I understand now that you have to be aware of which is
which.

I'm sure I'll hit more snags, but let's see if I can figure this out, now.

On Wed, Jun 9, 2010 at 7:44 PM, Ryan Culpepper <ryanc at ccs.neu.edu> wrote:
> On 06/09/2010 06:23 AM, Todd O'Bryan wrote:
>>
>> [...]
>>
>> ;; (define-aug-struct (sub sup)
>> ;;   ([field1 contract1]
>> ;;    [field2 contract2 default2]
>> ;;    ...))
>> ;;
>> ;; should be expanded to
>> ;;
>> ;; (define-syntax sub-info
>> ;;   '([field1 contract1] [field2 contract2 default2] ...))
>> ;;   so I can grab this info later to unify it with any sub-structs
>
> That's the problem. The contracts and defaults are expressions, but here
> you're quoting them, which throws away all of their lexical context
> information. Instead, you should produce something like this:
>
> (define-syntax sub-info
>  (list (list 'field1 (quote-syntax contract1))
>        (list 'field2 (quote-syntax contract2) (quote-syntax default2))
>        ___))
>
> quote-syntax is like quote, but it evaluates to syntax, and it preserves
> lexical context.
>
> In general, never call syntax->datum or use something else that has that
> effect (like quote) on anything you intend to treat as an *expression*.
>
> For example:
>
>> (define-syntax (define-aug-struct stx)
>>   (syntax-case stx ()
>>     [(_ (id super-id) field-info-syntax)
>>       ___
>>       [field-info (syntax->datum #'field-info-syntax)]
>
> field-info-syntax contains expressions; don't use syntax->datum.
> Instead, I'd rewrite the macro pattern to this:
>
>  (_ (id super-id) (field-spec ...))
>
> Then write a helper function that takes it apart using syntax-case,
> syntax->list, or something like that.
>
>>       [create-contract
>>        (cons '->
>>              (foldr append `(,(build-name #'id id-name "?"))
>>                     (map (λ (kw contr)
>>                            (list kw contr))
>>                          kw-names contracts)))]
>
> Using '-> (a symbol) actually happens to work here, but only because of
> the implicit coercion done by quasisyntax later. Looking just at this
> bit of code, I have to wonder: Do you apply some other, unexpected,
> lexical context later? What lexical context does quasiquote implicitly
> supply? Use #'-> instead, and the lexical context is (more) clear.*
>
> Ryan
>
>
> * To be fair, you still have to look to see if the macro is introducing
> a binding that shadows ->.
>


Posted on the users mailing list.