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.

Reply via email to