[racket] Advice how to refactor code to share pattern variables but split out templates?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Thu Sep 5 11:47:34 EDT 2013

Oh, wow, that is elegant.

Before seeing your post, I'd worked ahead on my own and came up with
something where the core helper function calls back to the
wrapper-provided higher-order function with a #'(LIST OF PATTEN VARS)
--- which the callee needs to syntax-case back into pattern variables
again:

https://github.com/greghendershott/def-jambda/commit/eda5bf8ce5668e49ba4068c50eab8055e34fcdc7

Although it works, it feels like using a list instead of a struct, and
using (match-define (list ....) x) instead of using struct field
accessors. With similar pros/cons. A con: It's fragile. If the list of
pattern variables were to change someday, it would break in a
less-helpful way. (Changing struct fields would still break, but more
helpfully. Adding a new field wouldn't break, at all.)

And so IIUC a syntax-class is the analog of a struct, for this.

Which was probably spelled out plainly on slide 2 of a presentation I
saw Ryan give years ago. O_o  But if so, at the time I only took away
the sense in which syntax-parse improves parsing details of
syntax-case.  I guess this is one of those cases where I had to try
the more-painful way myself, to be ready to learn/appreciate the
better way.

Cool!



On Wed, Sep 4, 2013 at 11:03 PM, Stephen Chang <stchang at ccs.neu.edu> wrote:
> Could you throw all the common parts into a syntax-class?
>
> That would enable you to put the cond branches in the defns
> themselves, which I agree is better.
>
> Something like this: https://gist.github.com/stchang/6445553
>
> I havent tested extensively but it seems to behave the same as your
> code on a few small examples.
>
> On Wed, Sep 4, 2013 at 8:37 PM, Greg Hendershott
> <greghendershott at gmail.com> wrote:
>> Given some macros that are wrappers around a core helper function:
>>
>> (define-syntax (wrapper1 stx)
>>   (core #f #f))
>> (define-syntax (wrapper2 stx)
>>   (core #f #t))
>> (define-syntax (wrapper3 stx)
>>   (core #t #f))
>> (define-syntax (wrapper4 stx)
>>   (core #t #t))
>>
>> (define-for-syntax (core stx opt1? opt2?)
>>   (define-syntax-class x ....)
>>   (syntax-parse stx
>>     [(_ pattern )
>>      (with-syntax*
>>        ([ <bunch of pattern variables> ])
>>        ;; Ugly cond using opt1? and opt2
>>        (cond [opt1? (cond [opt2? #'( <use ptn vars> )]
>>                           [else #'( <use ptn vars> )])]
>>              [else (cond [opt2? #'( <use ptn vars> )]
>>                          [else #'( <use ptn vars> )])]))]))
>>
>> Now I want/need to refactor the code. For one thing, some of the
>> wrappers must be in a file with `#lang racket`, and others in another
>> file with `#lang typed/racket`. Plus, the cond stuff is ugly; each
>> wrapper should handle this itself.  And in refactoring, of course I
>> want to D.R.Y. instead of copy pasta.
>>
>> The following seems somewhat better. Have the wrappers supply a
>> "callback" function to the core:
>>
>> ;; wrap12.rkt
>> #lang racket
>> (require "core.rkt")
>> (define-syntax (wrapper1 stx)
>>   (core (lambda (stx <bunch of pattern vars> )
>>           #'( <use ptn vars> ))))
>> .. wrapper2 similar ..
>>
>> ;; wrap34.rkt
>> #lang typed/racket
>> (require "core.rkt")
>> ... wrappers 3 4 similar ..
>>
>> ;; core.rkt
>> (provide core)
>> (define-for-syntax (core stx f)
>>   (define-syntax-class y ....)
>>   (syntax-parse stx
>>     [(_ pattern )
>>      (with-syntax*
>>        ([ <bunch of pattern variables> ])
>>        (f stx <bunch of pattern variables> ))])) ;; give back to the
>> caller and let it make the syntax
>>
>> And now it's easy for them to be in different files. However:
>>
>> 1. Now instead the ugly part is schlepping the pattern variables
>> around (e.g. half dozen function parameters).
>>
>> 2. Pattern variables and templates can't be separated like this and
>> still work, AFAICT.
>>
>> I have a few ideas that I'll go ahead and try, but I wanted to go
>> ahead and post this to see what ideas or advice anyone might have.
>>
>>
>> p.s. In case my question and code sketch here is too abstract, my
>> motivating full example is this:
>>
>> https://github.com/greghendershott/def-jambda/blob/50f6abcb7a64558756dce653c1faac4c012d4167/main.rkt
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/users

Posted on the users mailing list.