DEV Community

Andrew Shitov
Andrew Shitov

Posted on • Originally published at andrewshitov.com

Raku: a language that counts to infinity (Part 1)

We've already seen that Raku understands characters like , and it would be logically that you can use them with ease, similar to any other constructs of the language.

Take, for example, a sequence with no definite end. You define a pattern and take as many items as you need.

say (1, 1, * + * ... ∞)[^10];

Here, the pattern defines a Fibonacci sequence and we only take the first 10 elements of it:

(1 1 2 3 5 8 13 21 34 55)

You don't know upfront what the 10th element will be, so just say that the sequence is defined by the rule * + * and goes towards .

Need a stop at a given point? You can make the stop rule explicit:

say 1, 1, * + * ...^ * > 100;

Here we see the same sequence, but it stops as soon as the next number overcomes 100:

(1 1 2 3 5 8 13 21 34 55 89)

If you want to manipulate data a bit more elaborate than just taking the first few items, save the whole infinite list in a variable, why not? Use it as any other array in a Raku program:

my @fib = 1, 1, * + * ... ∞;
say @fib[5];
say @fib[55];

The program prints the requested 5th and 55th items of the sequence:

8
225851433717

The main difference with other elements is that the sequence that @fib hosts is lazy. It only computes the values when you demand it. Raku offers an easy way to check if it's lazy indeed:

my @fib = 1, 1, * + * ... ∞;
say @fib.is-lazy; # True

Working with lazy computations is very similar to any other "non-infinite" data. It's possible to map the values of an infinite sequence, say, square the numbers:

my @squares = (1 .. ∞).map(* ** 2);
say @squares[^5];
say @squares[999];

The program first prints the first five squares and then the item number 999, which is 1000²:

(1 4 9 16 25)
1000000

Let's try filtering a lazy sequence:

say (1 .. ∞).grep(*.is-prime)[^10];
say (1 .. ∞).grep(*.is-prime).first(* > 1000);

In this case, not only the original sequence 1 .. ∞ is lazy, but also it's filtered version (1 .. ∞).grep(*.is-prime). Use it in a similar manner as before:

(2 3 5 7 11 13 17 19 23 29)
1009

That's all for now. In Part 2, we'll see some more interesting things that you can do with lazy sequences.

Top comments (0)