Thanks, that was more obvious than I expected.

Aside from improving readability, the definition and use combined of the
macro-defining version comes out to about 40% of the original in terms of
lines of code, and it was trivial to have the same macro also expand into a
seperate submodule to generate the documentation automatically.

-Philip

On Mon, Sep 18, 2017 at 4:41 PM, Ryan Culpepper <ry...@ccs.neu.edu> wrote:

> On 09/17/2017 01:00 AM, Philip McGrath wrote:
>
>> [...]
>>
>> I have a macro like `example-macro`, but more complicated and with many,
>> many more potential keyword arguments, so I wanted to write a macro that
>> would let me define `example-macro` with a more declarative syntax, like
>> this:
>>
>> (define-example-macro/working generated-example-macro
>>    [#:a 'default-a symbol?]
>>    [#:b "default-b" string?])
>>
>> My initial attempt looked something like this:
>>
>> (define-syntax (define-example-macro/buggy stx)
>>    (define-syntax-class arg-clause
>>      (pattern [kw:keyword default:expr contract:expr]))
>>    (syntax-parse stx
>>      [(_ name clause:arg-clause ...+)
>>       ;#:with (arg ...) (generate-temporaries #'(clause.kw ...))
>>       ;#:with (arg.c ...) (generate-temporaries #'(clause.kw ...))
>>       #`(define-syntax name
>>           (syntax-parser
>>             [(_ (~alt (~optional
>>                        (~seq clause.kw (~var arg (expr/c
>> #'clause.contract)))
>>                        #:defaults ([arg.c #'clause.default]))
>>                       ...)
>>                 (... ...))
>>              #`(list arg.c ...)]))]))
>>
>> which raises a syntax error "syntax: no pattern variables before ellipsis
>> in template".
>>
>> The problem seems to be that `arg.c` is not recognized as a pattern
>> variable derived from `arg`. I tried several variants on this, none of
>> which allowed me to refer to `arg.c`. For example, if I uncomment the two
>> `#:with` lines, I get the error "~optional: attribute bound in defaults but
>> not in pattern".
>>
>
> If you uncomment the two "#:with" lines and look at the first expansion
> step of your example, you get the following:
>
>   (define-example-macro generated-example-macro
>     [#:a 'default-a symbol?]
>     [#:b "default-b" string?])
> =>
>   (define-syntax generated-example-macro
>      (syntax-parser
>       ((_
>         (~alt
>          (~optional
>           (~seq #:a (~var a5 (expr/c #'symbol?)))
>           #:defaults
>           ((a7 #''default-a)))
>          (~optional
>           (~seq #:b (~var b6 (expr/c #'string?)))
>           #:defaults
>           ((b8 #'"default-b"))))
>         ...)
>        #`(list a7 b8))))
>
> The problem is that a7 and b8 need to be a5.c and b6.c, respectively. So
> rather than two independent calls to generate-temporaries, you should build
> the arg.cs from the args:
>
>   #:with (arg ...) (generate-temporaries #'(clause.kw ...))
>   #:with (arg.c ...) (map (lambda (arg)
>                             (format-id arg "~a.c" arg))
>                           (syntax->list #'(arg ...)))
>
> Ryan
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to