Quick Tip #3: Inclusive and Exclusive

Every day of the Learning Perl 6 Kickstarter campaign, I’ll present a quick tip about something I like in Perl 6. Yesterday I posted Fancier sequences. In that post I only showed how you could use blocks to decide the next element in the sequence.

There’s some other interesting syntax that sequences and ranges (and a few other things). You already know how to make the fancy sequences, so I won’t distract you with that in this post. I’ll use simple, boring sequences for this post.

By default, the .. (Range) and ... (Sequence) operators include their end points. The range 0..9 includes the 0 and the 9. That’s mostly what you want and mostly what you expect.

Rather than writing programs, let’s look at these in the Perl 6 REPL. When you start perl6 without arguments, you drop into the perl6 shell:

$ perl6
To exit type 'exit' or '^D'
> 0 .. 9
0..9

The REPL shows the result of what I entered. In this case, it shows me the sequence although it has not evaluated it yet.

The list or flat methods will turn it into, well, a list. I can also assign it to a listy thing:

> (0..9).list
(0 1 2 3 4 5 6 7 8 9)
> (0..9).flat
(0 1 2 3 4 5 6 7 8 9)
> my @a = 0 .. 9;
[0 1 2 3 4 5 6 7 8 9]

You should have line history already (if not, See the FAQ), so you can arrow up to change the previous command without re-typing everything.

I try it again by including a ^ before the end element. This makes the end exclusive. It excludes the element from the list:

(0..^9).flat
(0 1 2 3 4 5 6 7 8) 

I can do the same on the other side to exclude the starting element:

> (0^..9).flat
(1 2 3 4 5 6 7 8 9)

Or I can do it on both sides:

> (0^..^9).flat
(1 2 3 4 5 6 7 8)

I can put spaces around the start or end elements:

> (0 ^..^ 9).flat
(1 2 3 4 5 6 7 8)

But not between the ^ and the ..:

> (0 ^.. ^9).flat
Range objects are not valid endpoints for Ranges

The operators are actually .., ^.., ..^, or ^..^.

I can use this to terminate the sequences as well. I already showed the infinite sequence. But, I can use a condition as the end point. When the condition is true, the sequence ends. In this case, it’s just a numerical comparison:

> ( 1 ... * > 15 ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)

And, if I don’t want to element that ends the sequence, I exclude it:

> ( 1 ...^ * > 15 ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)

I can have a block at the end, and I can exclude the value that makes the block true:

> ( 1 ... -> $a { $a > 15 } ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
> ( 1 ...^ -> $a { $a > 15 } ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)

But, the block can be anything that I like. I can terminate the sequence after a certain time passes:

> ( 1 ... -> $a { state $t = now; now > $t + 0.01 } ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
> ( 1 ... -> $a { state $t = now; now > $t + 0.02 } ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18)
> ( 1 ... -> $a { state $t = now; now > $t + 0.06 } ).list
(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 ...)

One comment

Leave a Reply to mscha Cancel reply

Your email address will not be published. Required fields are marked *