5

First:

$ raku -e "for 1...6, 7...15 { .say }"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Now:

$ raku -e "for 1...3, 7...15 { .say }"
1
2
3
7
11
15

I would expect this case to print 1,2,3,7,8,... 15.

What's happening here?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
zentrunix
  • 2,098
  • 12
  • 20
  • 2
    in second example loop is jumping from 3 to 7 (difference is 4), so in next iteration counter is incremented by 4, 7+4 == 11, 11+4-== 15 – Iłya Bursov Aug 27 '22 at 04:06
  • @IłyaBursov I don't think that's the reason: if you try with ` 1...4, 7...15` instead, end point 15 is included even though 4, 7, 10, 13(, 16...) doesn't include 15. I think something else is going on – Mustafa Aydın Aug 27 '22 at 10:55

3 Answers3

3

I think you might want the raku Range operator .. (two dots) and not the raku Sequence operator ... (three dots).

Here's how you examples look with the Range operator instead:

> raku -e 'for 1..6, 7..15 { .say }'
1..6
7..15

Oh, that's not good ... looks like for is just iterating over the two things 1..6 and 7..15 and stringifying them.

We can use a Slip | to fix that:

> raku -e 'for |(1..6), |(7..15) { .say }'
1
2
... (all the numbers)
14
15

And then:

raku -e 'for |(1..3), |(7..15) { .say }'
1
2
3
7
8
9
10
11
12
13
14
15

With the Sequence operator, you have made something like:

>raku -e 'for 3,7...15 { .say }'
3
7
11
15

That is raku for "make a sequence that starts with 3, then 7, then all the values until you get to the last at 15" ... and since the gap from 3 to 7 is 4, raku will count up in steps of 4. Then you began it with 1..3. ;-)

~p6steve

librasteve
  • 6,832
  • 8
  • 30
  • thanks ... `raku -e "for |^5, |^7 { .say }"` it's what I really wanted to do ... I had tried first with ranges, and it didn't work, then I tried with sequences, and it didn't work either... eventually I found out about `flat`, but I became curious about sequences – zentrunix Aug 27 '22 at 20:03
2

TL;DR This answer focuses on addressing what you originally asked (which was about "sequences") and precisely what the code you wrote is doing, rather than providing a solution (using ranges instead).

This is a work in progress dealing with something that seems both poorly documented and hard to fathom (which may explain part though not all of the doc situation). Please bear with me! (And I may just end up deleting this answer.)

1 ... 3, 7 ... 151 ... (3, 7) ... 15

In the absence of parentheses, operators within an expression are applied according to rules of "precedence" and "associativity".

Infix , has a higher precedence than infix ....¹ The above two lines of code thus produce the same result (1␤2␤3␤7␤11␤15␤):

for 1 ...  3, 7  ... 15 { .say }  # Operator evaluation by precedence
for 1 ... (3, 7) ... 15 { .say }  # Operator evaluation by parentheses

That said, while the result is what, given a glance at the code, I would expect based on my own "magical" DWIM ("Do What I Mean") thinking, I must say I don't yet know what the precise Raku(do)'s rule(s) are that lead to it DWIMing.

The doc for infix ... says:

If the endpoint is not *, it's smartmatched against each generated element and the sequence is terminated when the smartmatch succeeded.

But that seems overly simple. What if the endpoint of one sequence is another sequence? (As, at least taking a naive view, appears to be the case in your code.)

Also, as @MustafaAydin has noted:

how does your post explain the irregular last step size (of 2) instead of 3? I mean 4, 7 ... 15 alone produces (4, 7, 10, 13). But 1... 4, 7...15 now produces 7, 10, 13, 15 in the tail. Why is 15 included? Maybe i'm missing something idk

I'm at least as confused as Mustafa.

Indeed, I'm confused about several things. How come Raku(do) flattens the two sequences? [D'oh. Because the infix comma is higher precedence than the infix ....] Why doesn't it repeat the 3 in the final combined list? [Perhaps because multiple infix ...s are smart about what to do when there's an expression that's the endpoint of one sequence and the start of another?]

I'm going to go read the old design docs and/or spelunk roast and/or the Rakudo compiler code to see if I can see what's supposedly/actually going on. But not tonight.

Footnotes

¹ There's a table of operators in the current official operator doc. Supposedly this table:

summarizes the precedence levels offered by Raku, listing them in order from high to low precedence.

Unfortunately, at the time of writing this, the central operator table in the Operators page is profoundly wrong #4071.

Until that's fixed, here are "official" and "unofficial" options for determining the precedence of operators:

  • "official" Use in page search to search the official doc operator page for the operator of interest. Skip to the match in the entries on the left hand side of that same page. As you'll see, infix ,' is one level higher precedence than infix ...`:

    Comma operator precedence

    • infix ,

    • infix :

    List infix precedence

    • infix Z

    • infix X

    • infix ...

  • "unofficial" Look at the corresponding page of a staging site for an improved doc site. (I don't know how up to date it is, but the central table appears to list operators by precedence order as it claims.)

raiph
  • 31,607
  • 3
  • 62
  • 111
2

It's because it is two deductive sequences.

1...3

Is obviously a sequence where you add 1 to each successive value.

1, 2, 3

And since 7 is 4 more than 3, this is a sequence where you add 4 to each successive value.

3, 7 ... 15
3, 7, 11, 15

To get what you want, you could use a flattened Range.

1...3, |(7..15)

Or even a flattened Sequence.

1...3, |(7...15)
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • how does this post explain `1...4, 7...15` as `(1 2 3 4 7 10 13 15)` but not `(1 2 3 4 7 10 13)` – Mustafa Aydın Aug 27 '22 at 19:58
  • @raiph thanks but no; how does your post explain the irregular last step size (of 2) instead of 3? I mean `4, 7 ... 15` alone produces `(4, 7, 10, 13)`. But `1... 4, 7...15` now produces `7, 10, 13, 15)` in the tail. Why is 15 included? Maybe i'm missing something idk – Mustafa Aydın Aug 27 '22 at 20:37
  • the accidental joining of two Sequence operators smells wrong to me ... my guess is that this is a compiler bug that should error something like "badly specified Sequence" – librasteve Aug 27 '22 at 21:10
  • @p6steve I doubt it's a bug in the sense of an accident of how it works in Raku (the language) and Rakudo (the compiler). There's too much DWIMery going on (as touched on in my answer). I can't believe it's all a coincidence. So my current hypothesis is that the way Raku and Rakudo work is deliberate and there was .@Larry discussion of this, and the doc has simply omitted it, leaving it as an undocumented "feature". See my answer for what I'm (not) doing about all of this. – raiph Aug 27 '22 at 21:41
  • @raiph - IMO if you can't figure out on close analysis what this construct is intended to do, then even if there is an undocumented, but deliberate design call in play, IMO it is too esoteric to be of use (either due to lack of obviousness, or to lack of memorability) - so, in the absence of any documented feature, I continue to think the best action is to guard for this rather mysterious non-construct by reporting it as an error – librasteve Aug 31 '22 at 20:47
  • 1
    Hi @p6steve Imo what `foo ... bar ... baz` does DWIMs if one takes into account operator precedence. Also, that precedence is documented correctly in one place even though it's incorrect in another. I reported that incorrect documentation of precedence a while back. You say "rather mysterious non-construct" but that seems wrong. First, it's a construct, not a non-construct. It makes total sense to me, and, I'd argue, for anyone if the correct explanation is provided. Second, the only mystery for me was how it got it right. I've since figured that out. Again, it's simple and makes total sense. – raiph Sep 01 '22 at 11:29
  • Hi all - seems like my "smell" comment was me going off at half cock - sorry. Now that I have re-read raiph's answer I see that his explanation is clear and that he is not confused. Let me say how I see it now:- ```1 ... 3,7 ... 15``` is two sequence operators back to back. Since there is only ever one term to the right of a ```...``` the first operation is ```1 ... 3``` so that makes ```1,2,3```. The second operation is then ```3,7 ... 15``` so that makes ```3,7,11,15```. Since the ```3``` is not repeated in the source, this causes raku to not repeat it in the object. This makes sense – librasteve Sep 02 '22 at 17:27
  • 1
    to me now. I suppose it is intended as a way to have a continuum of sequence operators that makes a continuum of data points. So that is quite useful and not too unobvious. Sorry! _If we wanted to design down to the lowest common denominator it'd be Python._ Ha! – librasteve Sep 02 '22 at 17:30
  • ```say 1 ... 3, 7 ... 15, 11 ... 3 ... 1;``` says ```(1 2 3 7 11 15 11 7 3 2 1)``` – librasteve Sep 02 '22 at 17:42