[racket] macro help redux

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Wed Jun 9 19:44:36 EDT 2010

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.*


* 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.