Sooner or later you need to keep some state between an element and the next, generate some side effect, work with several data structures or, in general, work in a way that can’t be filtered using grep, mapped or reduced; or simply you need to perform some output during the processing of a data structure, something that can’t be done in the functions seen in the previous section. What you need is a for loop. But let’s talk first where and when you can use them.

Iterator is a role, and, as such and in general, are not intended to be used directly by programmers, but underlie a few, very useful, classes. The basic idea about iterators is that they are lists that can be traveled only once; they are going to be accessed sequentially, starting by the first element, and getting to the last one, which is marked as IterationEnd . The single most important function they have is pull-one, which extracts an element from them. In general, you will be able to iterate over structures that are appropriately called Iterable . Iterable is a role with a few methods, the most important of which is iterator, which converts any data structure in an, of course, Iterator. All that is happening under the hood when you use a for loop.

Let’s see a simple for loop:

.say for ^3 # 0␤1␤2␤

Where ␤ is a carriage return; that is, they will appear in separate lines. ^3 is a Range. Ranges implement the Iterator role, so what for is doing is actually calling ^3.iterator , which returns an Iterator. Every iteration, for calls pull-one on that iterator, until IterationEnd is reached.

Of course, even if that’s happening under the hood, you can also think that what for does is topicalizing, in turn, every element of the data structure it’s being applied to. And you can also use for in front, but in that case the syntax calls for using a block as the loop body.

for ^3 { .say } # 0␤1␤2␤

As is shown, this would be exactly the same result as before. We can combine this “doing” loop with a “producing” statement; when you need to create a data structure on the fly, the gather/take statements will do it. Gather will be used as the beginning of the loop, and will have a block inside where every take will produce a new element in a list.

say gather { take "this"; take "that" } (this that)

This will produce a list with two elements, one for every “take”. That’s not a loop, obviously, although it has got the same use case that loops would have in some other languages. You can use it with a loop, however

say gather { take "Number-$_" for 1..3 } # (Number-1 Number-2 Number-3)

In this case, we are using the topic variable created by the loop, $_, to generate a list of three strings; every time take is used a new string is generated, and they are all reunited in a single structure by gather.

Note: I initially wrote this mini-tutorial for the book "Perl 6 Quick Reference", which I'm writing for APress. However, it didn't fit the rest of the book. It might be useful anyway, so here it is.