3.2 KiB
Iterators
Iterators are one of the most powerful features of the Talc language and
standard library. An iterator is represented with a zero-argument function.
Every time the function is called it returns the next item in the sequence,
or the special value :end_iteration
to signal that no more items are
available.
An iterator can be created simply by defining such a function:
>> n = 0
0
>> fn counting() do
if n == 3 then
return :end_iteration
end
n += 1
n
end
<function counting(0) @5661c434f760>
>> counting()
1
>> counting()
2
>> counting()
3
>> counting()
:end_iteration
>> counting()
:end_iteration
Much like lists and ranges, iterators can be used in a for
loop. In fact,
lists and ranges are converted to iterators automatically by the for
loop.
This can be done manually using the built-in iter
function:
>> lst = [2, 3, 5]
[2, 3, 5]
>> lst_iter = iter(lst)
<native function iter[list](0) @5661c4352ef0>
>> lst_iter()
2
>> lst_iter()
3
>> lst_iter()
5
>> lst_iter()
:end_iteration
An iterator can be converted to a list using the list
function:
>> lst = [2, 3, 5]
[2, 3, 5]
>> list(iter(lst))
[2, 3, 5]
Iterator functions
The standard library includes many functions to manipulate iterators. Some essential ones are listed here. Examples will show both conventional call syntax as well as a version using a pipeline.
All standard library functions will take the iterator as the final argument.
Map
map
creates a new iterator from an existing one by passing each element
through a provided function.
>> list(map(\x -> x^2, [2, 3, 5]))
[4, 9, 25]
>> [2, 3, 5] | map(\x -> x^2) | list
[4, 9, 25]
Filter
filter
creates a new iterator only including values that, when passed to the
provided function, return a truthy value.
>> list(filter(\x -> x % 3 != 0, [1, 2, 3, 4, 5, 6]))
[1, 2, 4, 5]
>> [1, 2, 3, 4, 5, 6] | filter(\x -> x % 3 != 0) | list
[1, 2, 4, 5]
Fold
fold
consumes an iterator, applying a two-argument function repeatedly to its
values.
>> fold(\x,y -> x*y, [1, 2, 3, 4, 5, 6])
720
>> [1, 2, 3, 4, 5, 6] | fold(\x,y -> x*y)
720
foldi
does the same but allows an initial value to be specified.
>> foldi(11, \x,y -> x/y, [1, 2, 3, 4, 5, 6])
720
>> [1,2,3,4,5,6] | foldi(11, \x,y -> x/y)
720
sum
and prod
consume an iterator and return the sum or product of its
elements, respectively.
Forever and Take
forever
creates an iterator that returns the given value every time it is
called - an endless iterator. It is useful in combination with take
, which
creates an iterator that returns only the first n elements of its argument.
>> list(take(10, forever(42)))
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
>> forever(42) | take(10) | list
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
>> forever(42) | list -- bad idea!
Enumerate
enumerate
creates an iterator of two-element arrays, the first is the index
(starting from 0
) and the second is the item from the original iterator.
>> list(enumerate(["a", "b", "c"]))
[[0, "a"], [1, "b"], [2, "c"]]
>> ["a", "b", "c"] | enumerate | list
[[0, "a"], [1, "b"], [2, "c"]]