Thanks Alexis. To anyone who is in a position to look into this: it would be great if this can make it into the upcoming 7.5 release.
-- Jonathan On Sunday, October 13, 2019 at 4:08:00 AM UTC-4, Alexis King wrote: > > I think that error is a bug in syntax/parse. I have reported it here: > > https://github.com/racket/racket/issues/2856 > > On Oct 12, 2019, at 21:45, Jonathan Simpson <[email protected] > <javascript:>> wrote: > > I'm not sure exactly why my syntax class wasn't working, but it is working > now. I had an extra set of parentheses around the ~between pattern, so it > may have been related to that. Whatever the case may be, the non-splicing > syntax class is working now. > > I am very close to getting everything working but I am still having > trouble using ~between as part of a ~seq. Here's an example: > > (syntax-parse #'(1 2 'bar 4 5 'bar 'foo) [((~seq (~between x:integer 2 2) > ... z) ...+ expr) #'foo]) > ; >: contract violation > ; expected: real? > ; given: #<syntax:stdin::15625 2> > ; argument position: 1st > ; other arguments...: > ; 0 > > I want to match one or more sequences of two integers and an expression, > finally ending in one final expression. This is a contrived example but > demonstrates how I'll eventually need to use ~between. The syntax error I'm > getting here isn't particularly enlightening. > > Once again, I really appreciate any help here. > > -- Jonathan > > On Saturday, October 12, 2019 at 2:28:05 PM UTC-4, Alexis King wrote: >> >> 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]. >> 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] <javascript:>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/racket-users/f7c0b4ac-b11c-419a-b8e6-49176cd561fd%40googlegroups.com > > <https://groups.google.com/d/msgid/racket-users/f7c0b4ac-b11c-419a-b8e6-49176cd561fd%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/97712284-f977-45c6-a8b5-bb9d3e273830%40googlegroups.com.

