Course of Raku / Functional, concurrent, reactive, and web programming / Functional programming / Iterators
Writing an iterator
An iterator is simply an object that does the built-in
Iterator role and provides a pull-one method.
That method returns the next value, or IterationEnd when
there is nothing left. Here is a countdown iterator that yields a number
and steps towards zero:
class Countdown does Iterator {
has Int $.n is rw;
method pull-one {
return IterationEnd if $!n <= 0;
return $!n--;
}
}Each call to pull-one first checks whether the count has
run out; if not, it returns the current number and decrements it. The
post-decrement $!n-- returns the value before
subtracting, so the numbers come out 3, 2, 1. Driving it by
hand looks just like any other iterator:
my $c = Countdown.new(n => 3);
say $c.pull-one; # 3
say $c.pull-one; # 2
say $c.pull-one; # 1
say $c.pull-one =:= IterationEnd; # TrueAn iterator on its own is not something a for loop can
take directly — a loop expects an iterable. Wrap the iterator
in a Seq and it becomes loopable:
for Seq.new(Countdown.new(n => 3)) -> $x {
say $x;
}That prints 3, 2, 1. In
everyday code you would reach for gather /
take instead — the generator form is far shorter for the
same result. Writing the Iterator role directly is worth
seeing once, though, because it lays bare what gather,
map, and every for loop are built on: an
object that answers a single question — “what is the next value?”
Course navigation
← Quiz — The iterator protocol | Sum with pull-one →
💪 Or jump directly to the exercise
to this section.