I believe your two syntax classes are identical, except for the fact that the 
splicing variant will not be allowed as a single term pattern. Therefore, I 
don’t think there’s ever any reason to prefer the splicing version.

I tried an example using your mag-lvl syntax class with ~between, and it worked 
fine. This program successfully prints a list of length 3:

#lang racket

(require syntax/parse)

(define-syntax-class mag-lvl
  (pattern ({~datum level})))

(syntax-parse #'((level) (level) (level))
  [((~between lvls:mag-lvl 3 3) ...)
   (attribute lvls)])

So I’m not sure what problem you’re bumping into, and it’s not something I can 
guess without knowing more information.

> On Oct 12, 2019, at 11:13, Jonathan Simpson <[email protected]> wrote:
> 
> Regarding my custom syntax-class issue, I realize now that it is probably 
> because ~between only accepts splicing syntax classes. So, I created one that 
> matches my regular syntax class. I'm not 100 percent sure that these are 
> interchangeable in my use case though:
> 
> (define-syntax-class mag-lvl
>     (pattern ({~datum level})))
> 
> (define-splicing-syntax-class mag-slvl
>     (pattern ({~datum level})))
> 
> Does anyone know if :mag-slvl is interchangeable with :mag-lvl in most uses? 
> Are there cases where :mag-slvl won't work the way I expect it to. I'm not 
> confident in my understanding of the differences between using head patterns 
> and single term patterns.
> 
> -- Jonathan
> 
> On Friday, October 11, 2019 at 10:55:19 PM UTC-4, Jonathan Simpson wrote:
> Thank you Alexis for the clear explanation. I now understand how to use 
> ~between and it is working for me.
> 
> One small hitch I encountered is a custom syntax class I defined doesn't work 
> in the ~between statement but works elsewhere within the same syntax pattern. 
> This isn't a huge issue for me as I just copied the pattern in place of the 
> syntax class but I am curious why the :integer syntax class works and my 
> custom one doesn't.
> 
> Once again, thanks for taking the time to explain this!
> 
> -- Jonathan
> 
> On Thursday, October 10, 2019 at 11:17:53 PM UTC-4, Alexis King wrote:
> tl;dr: You need to use an ellipsis, so your pattern should be ((~between 
> x:integer 3 3) ...). A (much) more detailed explanation of why follows.
> 
> ~between is an ellipsis-head pattern. The most common ellipsis-head pattern, 
> ~optional, also works as a plain head pattern, but ~between does not. What’s 
> the difference?
> 
> Let’s start by answering what a head pattern is. The simplest kind of 
> syntax/parse pattern is a single-term pattern, which (as the name implies) 
> only matches a single syntax object at a time. Head patterns are special in 
> that they can match zero or more consecutive syntax objects in the head of a 
> list. What is the head of a list? Well, if you have a list like '(1 2 3 4), 
> its head is the sequence of elements “1 2 3 4” and its tail is simply the 
> empty list, '(). It’s possible to write the list '(1 2 3 4 . ()) to make that 
> more explicit.
> 
> So when you have a head pattern like (~optional x:integer), it might parse an 
> integer, but it also might parse nothing. In the latter case, the next head 
> pattern in the sequence would get a chance to parse the same element that 
> (~optional x:integer) did. Head patterns are able to do this because lists 
> introduce a kind of linear sequencing (not just tree-like nesting), so 
> “skipping” an element is an operation that makes sense.
> 
> But what about ellipsis-head patterns? These are patterns that don’t just 
> appear inside a list pattern, they appear inside a list pattern and under an 
> ellipsis. For example, in the pattern (x y ... z), x and z are head patterns, 
> but y is an ellipsis-head pattern. While head patterns introduce the ability 
> to consume one or more elements at a time, ellipsis-head patterns extend that 
> with the power to match elements in the list out of order. This is most 
> useful when parsing keyword options, such as in the following pattern:
> 
>     ((~alt (~once (~seq #:foo foo:integer)) (~once (~seq #:bar bar:string))) 
> ...)
> 
> The above pattern will match (#:foo 1 #:bar "two") or (#:bar "two" #:foo 1), 
> but not (#:foo 1) or (#:foo 1 #:foo 2 #:bar "three"). This is because ~alt 
> introduces a set of alternatives that can be matched, but unlike a simple 
> ~or* pattern, it also keeps track of how many times each case matched, and 
> patterns like ~once, ~optional, and ~between introduce constraints on the 
> number of times a given case must match for the overall parse to be 
> successful.
> 
> Interestingly, note that pattern variables bound under ~once and ~optional 
> don’t have an ellipsis depth of 1, they have an ellipsis depth of 0. This is 
> why, in the given example, you can refer to the foo and bar pattern variables 
> in a template without any ellipses. ~between, however, still increments the 
> ellipsis depth, since the pattern can actually match multiple times.
> 
> In the pattern I suggested at the beginning of this email, ((~between 
> x:integer 3 3) ...), you’re creating an ellipsis-head context with exactly 
> one alternative: (~between x:integer 3 3). That is exactly what you want, so 
> everything works out fine.
> 
> The one remaining question, however, is why ~between is only allowed as an 
> ellipsis-head pattern, but ~optional is also allowed as a head pattern. I 
> can’t say for certain, since you can think of ((~optional x:integer)) as 
> being sort of implicitly expanded to ((~optional x:integer) ...), and the 
> same could be done for ~between. However, my guess is that it isn’t allowed 
> because ~between increments the ellipsis depth of its sub-pattern, and Ryan 
> thought it would be confusing for a pattern variable’s ellipsis depth to be 
> incremented despite there not actually being any ellipses in the pattern. 
> Therefore, when using ~between, you have to write the ellipsis explicitly.
> 
> Alexis
> 
>> On Oct 10, 2019, at 20:37, Jonathan Simpson <[email protected] <>> wrote:
>> 
>> This seems like it should be simple but I've never been able to figure out 
>> how to do this. What I've been doing instead is this:
>> 
>> (x:integer ...+) to match two or more integers.
>> 
>> (x:integer y:integer ...+) to match three or more.
>> 
>> And so on.
>> 
>> I'm at a point now where I need to build patterns dynamically to match an 
>> exact number of elements. I'd also like to avoid having to create unique 
>> names for a bunch of pattern variables. ~between seems like what I want but 
>> I haven't been able to get it to work. I've been using ~seq without issue 
>> but that isn't exactly what I need.
>> 
>> Example of an attempt to use ~between:
>> 
>> (syntax-parse #'(1 1 1) [((~between x 3 3)) #'(x ...)])
>> ; stdin::2631: syntax-parse: pattern keyword not allowed here
>> ;   at: ~between
>> 
>> 
>> Can anyone give me a quick example of how to do this, using ~between or 
>> otherwise? I'm using syntax-parse, if that makes a difference.
>> 
>> Thanks!
>> 
>> -- Jonathan
> 
> 
> -- 
> 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 [email protected] 
> <mailto:[email protected]>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/871629c7-e004-421d-bb04-4496480390d1%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/racket-users/871629c7-e004-421d-bb04-4496480390d1%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/DE7636E0-D1CC-4EC9-95D0-27DDEF678AE8%40gmail.com.

Reply via email to