gleam/iterator
Types
An iterator is a lazily evaluated sequence of element.
Iterators are useful when working with collections that are too large to fit in memory (or those that are infinite in size) as they only require the elements currently being processed to be in memory.
As a lazy data structure no work is done when an iterator is filters,
mapped, etc, instead a new iterator is returned with these transformations
applied to the stream. Once the stream has all the required transformations
applied it can be evaluated using functions such as fold
and to_list
.
pub opaque type Iterator(element)
Functions
pub fn all(in iterator: Iterator(a), satisfying predicate: fn(a) ->
Bool) -> Bool
Returns True
if all elements emitted by the iterator satisfy the given predicate,
False
otherwise.
This function short-circuits once it finds a non-satisfying element.
An empty iterator results in True
.
Examples
> empty() |> all(fn(n) { n % 2 == 0 })
True
> from_list([2, 4, 6, 8]) |> all(fn(n) { n % 2 == 0 })
True
> from_list([2, 4, 5, 8]) |> all(fn(n) { n % 2 == 0 })
False
pub fn any(in iterator: Iterator(a), satisfying predicate: fn(a) ->
Bool) -> Bool
Returns True
if any element emitted by the iterator satisfies the given predicate,
False
otherwise.
This function short-circuits once it finds a satisfying element.
An empty iterator results in False
.
Examples
> empty() |> any(fn(n) { n % 2 == 0 })
False
> from_list([1, 2, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
True
> from_list([1, 3, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 })
False
pub fn append(to first: Iterator(a), suffix second: Iterator(a)) -> Iterator(
a,
)
Appends two iterators, producing a new iterator.
This function does not evaluate the elements of the iterators, the computation is performed when the resulting iterator is later run.
Examples
> [1, 2]
> |> from_list
> |> append([3, 4] |> from_list)
> |> to_list
[1, 2, 3, 4]
pub fn at(in iterator: Iterator(a), get index: Int) -> Result(
a,
Nil,
)
Returns nth element yielded by the given iterator, where 0
means the first element.
If there are not enough elements in the iterator, Error(Nil)
is returned.
For any index
less than 0
this function behaves as if it was set to 0
.
Examples
> from_list([1, 2, 3, 4]) |> at(2)
Ok(3)
> from_list([1, 2, 3, 4]) |> at(4)
Error(Nil)
> empty() |> at(0)
Error(Nil)
pub fn chunk(over iterator: Iterator(a), by f: fn(a) -> b) -> Iterator(
List(a),
)
Creates an iterator that emits chunks of elements
for which f
returns the same value.
Examples
> from_list([1, 2, 2, 3, 4, 4, 6, 7, 7])
> |> chunk(by: fn(n) { n % 2 })
> |> to_list
[[1], [2, 2], [3], [4, 4, 6], [7, 7]]
pub fn cycle(iterator: Iterator(a)) -> Iterator(a)
Creates an iterator that repeats a given iterator infinitely.
Examples
> [1, 2]
> |> from_list
> |> cycle
> |> take(6)
> |> to_list
[1, 2, 1, 2, 1, 2]
pub fn drop(from iterator: Iterator(a), up_to desired: Int) -> Iterator(
a,
)
Evaluates and discards the first N elements in an iterator, returning a new iterator.
If the iterator does not have enough elements an empty iterator is returned.
This function does not evaluate the elements of the iterator, the computation is performed when the iterator is later run.
Examples
> [1, 2, 3, 4, 5]
> |> from_list
> |> drop(up_to: 3)
> |> to_list
[4, 5]
> [1, 2]
> |> from_list
> |> drop(up_to: 3)
> |> to_list
[]
pub fn drop_while(in iterator: Iterator(a), satisfying predicate: fn(
a,
) -> Bool) -> Iterator(a)
Creates an iterator that drops elements while the predicate returns True
,
and then yields the remaining elements.
Examples
> from_list([1, 2, 3, 4, 2, 5])
> |> drop_while(satisfying: fn(x) { x < 4 })
> |> to_list
[4, 2, 5]
pub fn empty() -> Iterator(a)
Creates an iterator that yields no elements.
Examples
> empty() |> to_list
[]
pub fn filter(iterator: Iterator(a), for predicate: fn(a) -> Bool) -> Iterator(
a,
)
Creates an iterator from an existing iterator and a predicate function.
The new iterator will contain elements from the first iterator for which
the given function returns True
.
This function does not evaluate the elements of the iterator, the computation is performed when the iterator is later run.
Examples
> import gleam/int
> [1, 2, 3, 4]
> |> from_list
> |> filter(int.is_even)
> |> to_list
[2, 4]
pub fn find(in haystack: Iterator(a), one_that is_desired: fn(a) ->
Bool) -> Result(a, Nil)
Finds the first element in a given iterator for which the given function returns
True
.
Returns Error(Nil)
if the function does not return True
for any of the
elements.
Examples
> find(from_list([1, 2, 3]), fn(x) { x > 2 })
Ok(3)
> find(from_list([1, 2, 3]), fn(x) { x > 4 })
Error(Nil)
> find(empty(), fn(_) { True })
Error(Nil)
pub fn first(from iterator: Iterator(a)) -> Result(a, Nil)
Returns the first element yielded by the given iterator, if it exists,
or Error(Nil)
otherwise.
Examples
> from_list([1, 2, 3]) |> first
Ok(1)
> empty() |> first
Error(Nil)
pub fn flat_map(over iterator: Iterator(a), with f: fn(a) ->
Iterator(b)) -> Iterator(b)
Creates an iterator from an existing iterator and a transformation function.
Each element in the new iterator will be the result of calling the given function on the elements in the given iterator and then flattening the results.
This function does not evaluate the elements of the iterator, the computation is performed when the iterator is later run.
Examples
> [1, 2]
> |> from_list
> |> flat_map(fn(x) { from_list([x, x + 1]) })
> |> to_list
[1, 2, 2, 3]
pub fn flatten(iterator: Iterator(Iterator(a))) -> Iterator(a)
Flattens an iterator of iterators, creating a new iterator.
This function does not evaluate the elements of the iterator, the computation is performed when the iterator is later run.
Examples
> from_list([[1, 2], [3, 4]])
> |> map(from_list)
> |> flatten
> |> to_list
[1, 2, 3, 4]
pub fn fold(over iterator: Iterator(a), from initial: b, with f: fn(
b,
a,
) -> b) -> b
Reduces an iterator of elements into a single value by calling a given function on each element in turn.
If called on an iterator of infinite length then this function will never return.
If you do not care about the end value and only wish to evaluate the
iterator for side effects consider using the run
function instead.
Examples
> [1, 2, 3, 4]
> |> from_list
> |> fold(from: 0, with: fn(acc, element) { element + acc })
10
pub fn fold_until(over iterator: Iterator(a), from initial: b, with f: fn(
b,
a,
) -> ContinueOrStop(b)) -> b
Like fold
, fold_until
reduces an iterator of elements into a single value by calling a given
function on each element in turn, but uses list.ContinueOrStop
to determine
whether or not to keep iterating.
If called on an iterator of infinite length then this function will only ever
return if the function returns list.Stop
.
Examples
> import gleam/list
> let f = fn(acc, e) {
> case e {
> _ if e < 4 -> list.Continue(e + acc)
> _ -> list.Stop(acc)
> }
> }
>
> [1, 2, 3, 4]
> |> from_list
> |> fold_until(from: acc, with: f)
6
pub fn from_list(list: List(a)) -> Iterator(a)
Creates an iterator that yields each element from the given list.
Examples
> from_list([1, 2, 3, 4])
> |> to_list
[1, 2, 3, 4]
pub fn group(in iterator: Iterator(a), by key: fn(a) -> b) -> Map(
b,
List(a),
)
Returns a Map(k, List(element))
of elements from the given iterator
grouped with the given key function.
The order within each group is preserved from the iterator.
Examples
> from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 })
map.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])
pub fn index(over iterator: Iterator(a)) -> Iterator(#(Int, a))
Wraps values yielded from an iterator with indices, starting from 0.
Examples
> from_list(["a", "b", "c"]) |> index |> to_list
[#(0, "a"), #(1, "b"), #(2, "c")]
pub fn interleave(left: Iterator(a), with right: Iterator(a)) -> Iterator(
a,
)
Creates an iterator that alternates between the two given iterators until both have run out.
Examples
> from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list
[1, 11, 2, 12, 3, 13, 4, 14]
> from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list
[1, 100, 2, 3, 4]
pub fn intersperse(over iterator: Iterator(a), with elem: a) -> Iterator(
a,
)
Creates an iterator that yields the given elem
element
between elements emitted by the underlying iterator.
Examples
> empty()
> |> intersperse(with: 0)
> |> to_list
[]
> from_list([1])
> |> intersperse(with: 0)
> |> to_list
[1]
> from_list([1, 2, 3, 4, 5])
> |> intersperse(with: 0)
> |> to_list
[1, 0, 2, 0, 3, 0, 4, 0, 5]
pub fn iterate(from initial: a, with f: fn(a) -> a) -> Iterator(a)
Creates an iterator that inifinitely applies a function to a value.
Examples
> iterate(1, fn(n) { n * 3 }) |> take(5) |> to_list
[1, 3, 9, 27, 81]
pub fn last(iterator: Iterator(a)) -> Result(a, Nil)
Returns the last element in the given iterator.
Returns Error(Nil)
if the iterator is empty.
This function runs in linear time.
Examples
> empty() |> last
Error(Nil)
> range(1, 10) |> last
Ok(9)
pub fn length(over iterator: Iterator(a)) -> Int
Counts the number of elements in the given iterator.
This function has to traverse the entire iterator to count its elements, so it runs in linear time.
Examples
> empty() |> length
0
> from_list([1, 2, 3, 4]) |> length
4
pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(
b,
)
Creates an iterator from an existing iterator and a transformation function.
Each element in the new iterator will be the result of calling the given function on the elements in the given iterator.
This function does not evaluate the elements of the iterator, the computation is performed when the iterator is later run.
Examples
> [1, 2, 3]
> |> from_list
> |> map(fn(x) { x * 2 })
> |> to_list
[2, 4, 6]
pub fn once(f: fn() -> a) -> Iterator(a)
Creates an iterator that yields exactly one element provided by calling the given function.
Examples
> once(fn() { 1 }) |> to_list
[1]
pub fn range(from start: Int, to stop: Int) -> Iterator(Int)
Creates an iterator of ints, starting at a given start int and stepping by one to a given end int.
Examples
> range(from: 1, to: 5) |> to_list
[1, 2, 3, 4, 5]
> range(from: 1, to: -2) |> to_list
[1, 0, -1, -2]
> range(from: 0, to: 0) |> to_list
[0]
pub fn reduce(over iterator: Iterator(a), with f: fn(a, a) -> a) -> Result(
a,
Nil,
)
This function acts similar to fold, but does not take an initial state.
Instead, it starts from the first yielded element
and combines it with each subsequent element in turn using the given function.
The function is called as f(accumulator, current_element)
.
Returns Ok
to indicate a successful run, and Error
if called on an empty iterator.
Examples
> from_list([]) |> reduce(fn(acc, x) { acc + x })
Error(Nil)
> from_list([1, 2, 3, 4, 5]) |> reduce(fn(acc, x) { acc + x })
Ok(15)
pub fn repeat(x: a) -> Iterator(a)
Creates an iterator that returns the same value infinitely.
Examples
> repeat(10)
> |> take(4)
> |> to_list
[10, 10, 10, 10]
pub fn repeatedly(f: fn() -> a) -> Iterator(a)
Creates an iterator that yields values created by calling a given function repeatedly.
pub fn run(iterator: Iterator(a)) -> Nil
Evaluates all elements emitted by the given iterator. This function is useful for when you wish to trigger any side effects that would occur when evaluating the iterator.
pub fn scan(over iterator: Iterator(a), from initial: b, with f: fn(
b,
a,
) -> b) -> Iterator(b)
Creates an iterator from an existing iterator and a stateful function.
Specifically, this behaves like fold
, but yields intermediate results.
Examples
// Generate a sequence of partial sums
> from_list([1, 2, 3, 4, 5])
> |> scan(from: 0, with: fn(acc, el) { acc + el })
> |> to_list
[1, 3, 6, 10, 15]
pub fn single(elem: a) -> Iterator(a)
Creates an iterator that yields the given element exactly once.
Examples
> single(1) |> to_list
[1]
pub fn sized_chunk(over iterator: Iterator(a), into count: Int) -> Iterator(
List(a),
)
Creates an iterator that emits chunks of given size.
If the last chunk does not have count
elements, it is yielded
as a partial chunk, with less than count
elements.
For any count
less than 1 this function behaves as if it was set to 1.
Examples
> from_list([1, 2, 3, 4, 5, 6])
> |> sized_chunk(into: 2)
> |> to_list
[[1, 2], [3, 4], [5, 6]]
> from_list([1, 2, 3, 4, 5, 6, 7, 8])
> |> sized_chunk(into: 3)
> |> to_list
[[1, 2, 3], [4, 5, 6], [7, 8]]
pub fn step(iterator: Iterator(a)) -> Step(a, Iterator(a))
Eagerly accesses the first value of an interator, returning a Next
that contains the first value and the rest of the iterator.
If called on an empty iterator, Done
is returned.
Examples
> assert Next(head, tail) = [1, 2, 3, 4]
> |> from_list
> |> step
> head
1
> tail |> to_list
[2, 3, 4]
> empty() |> step
Done
pub fn take(from iterator: Iterator(a), up_to desired: Int) -> Iterator(
a,
)
Creates an iterator that only yields the first desired
elements.
If the iterator does not have enough elements all of them are yielded.
Examples
> [1, 2, 3, 4, 5]
> |> from_list
> |> take(up_to: 3)
> |> to_list
[1, 2, 3]
> [1, 2]
> |> from_list
> |> take(up_to: 3)
> |> to_list
[1, 2]
pub fn take_while(in iterator: Iterator(a), satisfying predicate: fn(
a,
) -> Bool) -> Iterator(a)
Creates an iterator that yields elements while the predicate returns True
.
Examples
> from_list([1, 2, 3, 2, 4])
> |> take_while(satisfying: fn(x) { x < 3 })
> |> to_list
[1, 2]
pub fn to_list(iterator: Iterator(a)) -> List(a)
Evaluates an iterator and returns all the elements as a list.
If called on an iterator of infinite length then this function will never return.
Examples
> [1, 2, 3]
> |> from_list
> |> map(fn(x) { x * 2 })
> |> to_list
[2, 4, 6]
pub fn transform(over iterator: Iterator(a), from initial: b, with f: fn(
b,
a,
) -> Step(c, b)) -> Iterator(c)
Creates an iterator from an existing iterator and a stateful function that may short-circuit.
f
takes arguments acc
for current state and el
for current element from underlying iterator,
and returns either Next
with yielded element and new state value, or Done
to halt the iterator.
Examples
Approximate implementation of index
in terms of transform
:
> from_list(["a", "b", "c"])
> |> transform(0, fn(i, el) { Next(#(i, el), i + 1) })
> |> to_list
[#(0, "a"), #(1, "b"), #(2, "c")]
pub fn try_fold(over iterator: Iterator(a), from initial: b, with f: fn(
b,
a,
) -> Result(b, c)) -> Result(b, c)
A variant of fold that might fail.
The folding function should return Result(accumulator, error)
.
If the returned value is Ok(accumulator)
try_fold will try the next value in the iterator.
If the returned value is Error(error)
try_fold will stop and return that error.
Examples
> [1, 2, 3, 4]
> |> iterator.from_list()
> |> try_fold(0, fn(acc, i) {
> case i < 3 {
> True -> Ok(acc + i)
> False -> Error(Nil)
> }
> })
Error(Nil)
pub fn unfold(from initial: a, with f: fn(a) -> Step(b, a)) -> Iterator(
b,
)
Creates an iterator from a given function and accumulator.
The function is called on the accumulator and returns either Done
,
indicating the iterator has no more elements, or Next
which contains a
new element and accumulator. The element is yielded by the iterator and the
new accumulator is used with the function to compute the next element in
the sequence.
Examples
> unfold(from: 5, with: fn(n) {
> case n {
> 0 -> Done
> n -> Next(element: n, accumulator: n - 1)
> }
> })
> |> to_list
[5, 4, 3, 2, 1]