[racket] syntax/parse ~or patterns

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Thu Jun 9 22:27:49 EDT 2011

Nadeem,

You're mixing "..." repetition with mapping some kind of operation
over each element, and that doesn't work, at least not directly.
Also, the way you've used ~or does not preserve the ordering of
elements.  Instead, the attributes a and b just get all the a/b pairs,
and c gets all the c elements, but there is no record of how they were
interleaved.  So for instance, you could write:

  (syntax-parse stx
    [(_ (~or (a b) c) ...)
     #'(list (+ a b) ... (- c) ...)])

That would turn (my-macro (4 5) 6 (1 2)) into (list (+ 4 5) (+ 1 2) (-
6)).  If the order doesn't matter, that works.  If not, you need
another approach.

I suggest turning each element into a syntax class.  A syntax class is
itself a macro definition, but it has to go in the macro phase.  There
are a number of ways to do this; one way is with an internal
definition.

  (define-syntax (my-macro stx)

    (define-syntax-class elem #:attributes [output]
      (pattern [a b] #:attr output #'(+ a b))
      (pattern c #:attr output #'(- c)))

    (syntax-parse stx
      [(_ e:elem ...)
       #'(list e.output ...)]))

That should give you the results you want.  The syntax class does the
operation on each element, so it gives you back the power of map using
"...".

Hope this helps,
Carl Eastlund

On Thu, Jun 9, 2011 at 10:18 PM, Nadeem Abdul Hamid <nadeem at acm.org> wrote:
> I'm struggling with figuring out how to work with ~or patterns and
> syntax/parse. Suppose, for example, I want to write a macro that takes
> any number of either single numbers or pairs of numbers. It should
> expand into a list of results where each single number is negated and
> each pair is summed together. Examples:
>
> (my-macro (4 5))  ; expands to ==>  (list (+ 4 5))
> (my-macro 6)      ; expands to ==> (list (- 6))
> (my-macro (4 5) 6 (1 2)) ; expands to ==>  (list (+ 4 5) (- 6) (+ 1 2))
>
> So, I start writing a syntax-parse pattern like this:
>
> (define-syntax (my-macro stx)
>  (syntax-parse stx
>    [(my-macro (~or (a b) c) ...+)
>     #`(list ... ???
>
> I'm stuck on how to distinguish which situation matched in the ~or --
> I've tried using 'attribute' but no matter what I do, I get problems
> with either the ellipses or "pattern variables used outside of
> template" or something else. I thought that something like this should
> have worked:
>
>     #`(list #,(if (attribute c) #`(- c) #`(+ a b)) ...)]))
>
> But the ellipses are a problem. I see at the very bottom of section
> 8.4 in the "Syntax" library documentation
> (http://docs.racket-lang.org/syntax/stxparse-specifying.html) that
> there's something funky about ellipses nesting depth and ~or. So I
> tried using  #, with (attribute ...) around all occurrences of c, a,
> and b, and got rid of the ... and that gets me closer, but the macro
> doesn't expand properly. That is, with a mess like this:
>
> (define-syntax (my-macro stx)
>  (syntax-parse stx
>    [(my-macro (~or (a b) c) ...+)
>     #`(list
>        #,(if (attribute c)
>              #`(- #,(attribute c))
>              #`(+ #,(attribute a) #,(attribute b))) )]))
>
> I get
>   (my-macro (4 5) 6 (1 2))
> expanding to
>   (list (- (#f 6 #f)))
>
> I kind of see what's happening, but is 'attribute' the appropriate way
> to go here?
>
> Help!
>
> --- nadeem
> _________________________________________________
>  For list-related administrative tasks:
>  http://lists.racket-lang.org/listinfo/users
>
>



Posted on the users mailing list.