Centenary Sequences with Raku
Part 1

Raku

by Arne Sommer

Centenary Sequences with Raku - Part 1: Raku

[100.1] Published 4. November 2020.

See also: The Introduction.

Range vs Sequence

Raku has two built in types we can use to generate sequences:

  • Range: Consecutive increasing integers only, generated with the .. operator.
  • Sequence: Numeric values in any form and/or order, generated with the ... operator.

Note that both the .. and the ... operators are binary. They take two parameters, one on each side of the operator:

> say (1 .. 10);   # -> (1 2 3 4 5 6 7 8 9 10)
> say (1 ... 10);  # -> (1 2 3 4 5 6 7 8 9 10)

Raku Ranges and Sequences can be of infinite length:

> say (0 ..   Inf)[^10];  # -> (0 1 2 3 4 5 6 7 8 9)

A Range cannot count down, but a Sequence can:

> say (0 ..  -Inf)[^10];  # -> (Nil Nil Nil Nil Nil Nil Nil Nil Nil Nil)
> say (0 ... -Inf)[^10];  # -> (0 -1 -2 -3 -4 -5 -6 -7 -8 -9)

See docs.raku.org/type/Range for more information about the Range type.

See docs.raku.org/type/Sequence for more information about the Sequence type.

Usage

The simplest use case is a loop that should be run a specific number of times.

The traditional method is the C-style loop, which is available as loop in Raku:

loop (my $i=1; $i <= 10; $i++) { say $i }

This will print the numbers 1 to 10, each on its own line.

We can use a Range instead, in combination with the Raku for iterator like this:

for 1 .. 10 -> $i { say $i }

If we are only interested in the number of iterations, the Range Upto Operator ^ is pretty neat:

for ^10 -> $i { say $i }  # The same as (0 .. 9)

As long as you are OK with the numbers starting at zero, and ending one below the given upto limit.

See docs.raku.org/syntax/loop for more information about the loop keyword.

See docs.raku.org/routine/^ for more information about the Upto Operator ^.

Lazy Data Structures

Infinite data structures, as shown above with infinity as the upper limit, are fine as we get a lazy data structure - where the values are only computed when actually used).

Printing a lazy data structure does not give us any values:

say (1 .. Inf);  # -> 1..Inf
put (1 .. Inf);  # -> 1..*

Note the alternate symbol for infinity: *, used by put. You can use whichever you want, *, Inf - or even the Unicode symbol (U+221E).

We can print the first 10 values of an infinite Range like this:

say (1 .. Inf)[^10];  # -> (1 2 3 4 5 6 7 8 9 10)
put (1 .. Inf)[^10];  # -> 1 2 3 4 5 6 7 8 9 10

You can ask Raku if the data structure is lazy, with the is-lazy method if you are in doubt:

say (1 .. Inf).is-lazy;       # -> True
say (1 .. Inf)[^10].is-lazy;  # -> False

See docs.raku.org/routine/is-lazy for more information about the is-lazy method.

put vs say

Note that say will not always print what we give it, but put will:

> say (1 .. Inf)[^110];
(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 ...)
> put (1 .. Inf)[^110];
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 101 102 \
103 104 105 106 107 108 109 110

The Next Part

Part 2: Arithmetic and Geometric Sequences.