> (prefix 6 5 4) raises the same error as before, and the definition of > prefix/parse complains "syntax-parse: duplicate attribute in: tail".
This is because ~or behaves differently under ellipses, and nested ~or are just inlined. Your code for prefix/parse is therefore equivalent to (~or alt1 (~seq #:tail) (~and (~seq) (~parse tail #'null))) ... To make a ~or pattern behave as a normal ~or, and not as a list of possibly-repeated elements, you can wrap it with a dummy ~and, i.e. writing (~or alt1 alt2 (~and (~or foo bar)) alt4) ... instead of (~or alt1 alt2 (~or foo bar) alt4) ... I like to define a (~either . pats) pattern expander which aliases to (~and (~or . pats)), for better readability [1] . In your case, since you want to limit it to a single occurrence anyway, you can simply wrap the inner ~or with ~once, as follows: #lang racket (require (for-syntax syntax/parse)) (define-syntax (prefix/parse stx) (syntax-parse stx [(_ (~or (~seq nat:exact-nonnegative-integer) (~once (~or (~seq #:tail tail) (~and (~seq) (~parse tail #'null))))) ...) #:declare tail (expr/c #'(listof natural-number/c)) #'(list* nat ... tail.c)])) The issue with this solution, however, is that it allows the empty sequence (~seq) to be matched as part of a ellipsis-head pattern. This means that the (~seq) could match anywhere, and, save for the ~once, could match an infinite amount of times without consuming any element. To prevent such issues, syntax/parse guards against this, and you will get the following error: syntax-parse: an ellipsis-head pattern matched an empty sequence The simplest solution I can see is to re-bind the tail attribute to a real pattern variable, safe in the knowledge that the tail attribute is never #f, thanks to the #:defaults (note that if you nest uses of ~optional, e.g. (~optional (~seq (~seq a (~optional b #:defaults ([b c]))) ...)), then I think this is not true anymore, you'd have to provide #:defaults for the outer ~optional too. I'll use #:with here, but you could equally use a {~parse pvar-tail #'tail) in the pattern, somewhere after the (~or . pats) ...: #lang racket (require (for-syntax syntax/parse)) (define-syntax (prefix/parse stx) (syntax-parse stx [(_ (~or (~seq nat:exact-nonnegative-integer) (~optional (~seq #:tail tail) #:defaults ([tail #'null]))) ...) #:with pvar-tail #'tail #:declare pvar-tail (expr/c #'(listof natural-number/c)) #'(list* nat ... pvar-tail.c)])) (prefix/parse 1 2 3) (prefix/parse 1 2 3 #:tail 42) ;; contract violation, as expected. It would probably be possible to abstract this using my extensible-parser-specifications library [2] which defines a ~seq-no-order similar to the one by Alexander Knauth, but allows some "post" operations which are executed after matching the whole sequence. I would recommend against it, however, as my library has severe limitations, and could really use a redesign (which might need some changes in syntax/parse itself, as achieving these "post" operations required a few hacks). Alternatively, it would make sense to fix #:declare so that it handles gracefully #f values. Could you file an issue for this so that it is not forgotten? [1]: http://docs.racket-lang.org/phc-toolkit/syntax-parse_helpers.html#%28form._%28%28submod._%28lib._phc-toolkit%2Fsyntax-parse..rkt%29._typed%29._~7eeither%29%29 [2]: http://docs.racket-lang.org/extensible-parser-specifications/ -- 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.