gleam/yielder

Types

pub type Step(element, accumulator) {
  Next(element: element, accumulator: accumulator)
  Done
}

Constructors

  • Next(element: element, accumulator: accumulator)
  • Done

An yielder is a lazily evaluated sequence of element.

Yielders 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 yielder is filtered, mapped, etc, instead a new yielder 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 Yielder(element)

Functions

pub fn all(
  in yielder: Yielder(a),
  satisfying predicate: fn(a) -> Bool,
) -> Bool

Returns True if all elements emitted by the yielder satisfy the given predicate, False otherwise.

This function short-circuits once it finds a non-satisfying element.

An empty yielder 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 yielder: Yielder(a),
  satisfying predicate: fn(a) -> Bool,
) -> Bool

Returns True if any element emitted by the yielder satisfies the given predicate, False otherwise.

This function short-circuits once it finds a satisfying element.

An empty yielder 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: Yielder(a),
  suffix second: Yielder(a),
) -> Yielder(a)

Appends two yielders, producing a new yielder.

This function does not evaluate the elements of the yielders, the computation is performed when the resulting yielder is later run.

Examples

from_list([1, 2])
|> append(from_list([3, 4]))
|> to_list
// -> [1, 2, 3, 4]
pub fn at(
  in yielder: Yielder(a),
  get index: Int,
) -> Result(a, Nil)

Returns nth element yielded by the given yielder, where 0 means the first element.

If there are not enough elements in the yielder, 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 yielder: Yielder(a),
  by f: fn(a) -> b,
) -> Yielder(List(a))

Creates an yielder 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 concat(yielders: List(Yielder(a))) -> Yielder(a)

Joins a list of yielders into a single yielder.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

[[1, 2], [3, 4]]
|> map(from_list)
|> concat
|> to_list
// -> [1, 2, 3, 4]
pub fn cycle(yielder: Yielder(a)) -> Yielder(a)

Creates an yielder that repeats a given yielder infinitely.

Examples

from_list([1, 2])
|> cycle
|> take(6)
|> to_list
// -> [1, 2, 1, 2, 1, 2]
pub fn drop(
  from yielder: Yielder(a),
  up_to desired: Int,
) -> Yielder(a)

Evaluates and discards the first N elements in an yielder, returning a new yielder.

If the yielder does not have enough elements an empty yielder is returned.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

from_list([1, 2, 3, 4, 5])
|> drop(up_to: 3)
|> to_list
// -> [4, 5]
from_list([1, 2])
|> drop(up_to: 3)
|> to_list
// -> []
pub fn drop_while(
  in yielder: Yielder(a),
  satisfying predicate: fn(a) -> Bool,
) -> Yielder(a)

Creates an yielder 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 each(over yielder: Yielder(a), with f: fn(a) -> b) -> Nil

Traverse an yielder, calling a function on each element.

Examples

empty() |> each(io.println)
// -> Nil
from_list(["Tom", "Malory", "Louis"]) |> each(io.println)
// -> Nil
// Tom
// Malory
// Louis
pub fn empty() -> Yielder(a)

Creates an yielder that yields no elements.

Examples

empty() |> to_list
// -> []
pub fn filter(
  yielder: Yielder(a),
  keeping predicate: fn(a) -> Bool,
) -> Yielder(a)

Creates an yielder from an existing yielder and a predicate function.

The new yielder will contain elements from the first yielder for which the given function returns True.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

import gleam/int

from_list([1, 2, 3, 4])
|> filter(int.is_even)
|> to_list
// -> [2, 4]
pub fn filter_map(
  yielder: Yielder(a),
  keeping_with f: fn(a) -> Result(b, c),
) -> Yielder(b)

Creates an yielder from an existing yielder and a transforming predicate function.

The new yielder will contain elements from the first yielder for which the given function returns Ok, transformed to the value inside the Ok.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

import gleam/string
import gleam/int

"a1b2c3d4e5f"
|> string.to_graphemes
|> from_list
|> filter_map(int.parse)
|> to_list
// -> [1, 2, 3, 4, 5]
pub fn find(
  in haystack: Yielder(a),
  one_that is_desired: fn(a) -> Bool,
) -> Result(a, Nil)

Finds the first element in a given yielder 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 find_map(
  in haystack: Yielder(a),
  one_that is_desired: fn(a) -> Result(b, c),
) -> Result(b, Nil)

Finds the first element in a given yielder for which the given function returns Ok(new_value), then returns the wrapped new_value.

Returns Error(Nil) if no such element is found.

Examples

find_map(from_list(["a", "1", "2"]), int.parse)
// -> Ok(1)
find_map(from_list(["a", "b", "c"]), int.parse)
// -> Error(Nil)
find_map(from_list([]), int.parse)
// -> Error(Nil)
pub fn first(from yielder: Yielder(a)) -> Result(a, Nil)

Returns the first element yielded by the given yielder, 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 yielder: Yielder(a),
  with f: fn(a) -> Yielder(b),
) -> Yielder(b)

Creates an yielder from an existing yielder and a transformation function.

Each element in the new yielder will be the result of calling the given function on the elements in the given yielder and then flattening the results.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

from_list([1, 2])
|> flat_map(fn(x) { from_list([x, x + 1]) })
|> to_list
// -> [1, 2, 2, 3]
pub fn flatten(yielder: Yielder(Yielder(a))) -> Yielder(a)

Flattens an yielder of yielders, creating a new yielder.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

from_list([[1, 2], [3, 4]])
|> map(from_list)
|> flatten
|> to_list
// -> [1, 2, 3, 4]
pub fn fold(
  over yielder: Yielder(a),
  from initial: b,
  with f: fn(b, a) -> b,
) -> b

Reduces an yielder of elements into a single value by calling a given function on each element in turn.

If called on an yielder of infinite length then this function will never return.

If you do not care about the end value and only wish to evaluate the yielder for side effects consider using the run function instead.

Examples

from_list([1, 2, 3, 4])
|> fold(from: 0, with: fn(acc, element) { element + acc })
// -> 10
pub fn fold_until(
  over yielder: Yielder(a),
  from initial: b,
  with f: fn(b, a) -> ContinueOrStop(b),
) -> b

Like fold, fold_until reduces an yielder 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 yielder 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)
  }
}

from_list([1, 2, 3, 4])
|> fold_until(from: 0, with: f)
// -> 6
pub fn from_list(list: List(a)) -> Yielder(a)

Creates an yielder 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 yielder: Yielder(a),
  by key: fn(a) -> b,
) -> Dict(b, List(a))

Returns a Dict(k, List(element)) of elements from the given yielder grouped with the given key function.

The order within each group is preserved from the yielder.

Examples

from_list([1, 2, 3, 4, 5, 6])
|> group(by: fn(n) { n % 3 })
// -> dict.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])
pub fn index(over yielder: Yielder(a)) -> Yielder(#(a, Int))

Wraps values yielded from an yielder with indices, starting from 0.

Examples

from_list(["a", "b", "c"]) |> index |> to_list
// -> [#("a", 0), #("b", 1), #("c", 2)]
pub fn interleave(
  left: Yielder(a),
  with right: Yielder(a),
) -> Yielder(a)

Creates an yielder that alternates between the two given yielders 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 yielder: Yielder(a),
  with elem: a,
) -> Yielder(a)

Creates an yielder that yields the given elem element between elements emitted by the underlying yielder.

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) -> Yielder(a)

Creates an yielder that infinitely 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(yielder: Yielder(a)) -> Result(a, Nil)

Returns the last element in the given yielder.

Returns Error(Nil) if the yielder is empty.

This function runs in linear time.

Examples

empty() |> last
// -> Error(Nil)
range(1, 10) |> last
// -> Ok(10)
pub fn length(over yielder: Yielder(a)) -> Int

Counts the number of elements in the given yielder.

This function has to traverse the entire yielder 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 yielder: Yielder(a),
  with f: fn(a) -> b,
) -> Yielder(b)

Creates an yielder from an existing yielder and a transformation function.

Each element in the new yielder will be the result of calling the given function on the elements in the given yielder.

This function does not evaluate the elements of the yielder, the computation is performed when the yielder is later run.

Examples

from_list([1, 2, 3])
|> map(fn(x) { x * 2 })
|> to_list
// -> [2, 4, 6]
pub fn map2(
  yielder1: Yielder(a),
  yielder2: Yielder(b),
  with fun: fn(a, b) -> c,
) -> Yielder(c)

Combines two yielders into a single one using the given function.

If an yielder is longer than the other the extra elements are dropped.

This function does not evaluate the elements of the two yielders, the computation is performed when the resulting yielder is later run.

Examples

let first = from_list([1, 2, 3])
let second = from_list([4, 5, 6])
map2(first, second, fn(x, y) { x + y }) |> to_list
// -> [5, 7, 9]
let first = from_list([1, 2])
let second = from_list(["a", "b", "c"])
map2(first, second, fn(i, x) { #(i, x) }) |> to_list
// -> [#(1, "a"), #(2, "b")]
pub fn once(f: fn() -> a) -> Yielder(a)

Creates an yielder 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) -> Yielder(Int)

Creates an yielder 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 yielder: Yielder(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 yielder.

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) -> Yielder(a)

Creates an yielder that returns the same value infinitely.

Examples

repeat(10)
|> take(4)
|> to_list
// -> [10, 10, 10, 10]
pub fn repeatedly(f: fn() -> a) -> Yielder(a)

Creates an yielder that yields values created by calling a given function repeatedly.

repeatedly(fn() { 7 })
|> take(3)
|> to_list
// -> [7, 7, 7]
pub fn run(yielder: Yielder(a)) -> Nil

Evaluates all elements emitted by the given yielder. This function is useful for when you wish to trigger any side effects that would occur when evaluating the yielder.

pub fn scan(
  over yielder: Yielder(a),
  from initial: b,
  with f: fn(b, a) -> b,
) -> Yielder(b)

Creates an yielder from an existing yielder 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) -> Yielder(a)

Creates an yielder that yields the given element exactly once.

Examples

single(1) |> to_list
// -> [1]
pub fn sized_chunk(
  over yielder: Yielder(a),
  into count: Int,
) -> Yielder(List(a))

Creates an yielder 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(yielder: Yielder(a)) -> Step(a, Yielder(a))

Eagerly accesses the first value of an yielder, returning a Next that contains the first value and the rest of the yielder.

If called on an empty yielder, Done is returned.

Examples

let assert Next(first, rest) = from_list([1, 2, 3, 4]) |> step

first
// -> 1

rest |> to_list
// -> [2, 3, 4]
empty() |> step
// -> Done
pub fn take(
  from yielder: Yielder(a),
  up_to desired: Int,
) -> Yielder(a)

Creates an yielder that only yields the first desired elements.

If the yielder does not have enough elements all of them are yielded.

Examples

from_list([1, 2, 3, 4, 5])
|> take(up_to: 3)
|> to_list
// -> [1, 2, 3]
from_list([1, 2])
|> take(up_to: 3)
|> to_list
// -> [1, 2]
pub fn take_while(
  in yielder: Yielder(a),
  satisfying predicate: fn(a) -> Bool,
) -> Yielder(a)

Creates an yielder 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(yielder: Yielder(a)) -> List(a)

Evaluates an yielder and returns all the elements as a list.

If called on an yielder of infinite length then this function will never return.

Examples

from_list([1, 2, 3])
|> map(fn(x) { x * 2 })
|> to_list
// -> [2, 4, 6]
pub fn transform(
  over yielder: Yielder(a),
  from initial: b,
  with f: fn(b, a) -> Step(c, b),
) -> Yielder(c)

Creates an yielder from an existing yielder and a stateful function that may short-circuit.

f takes arguments acc for current state and el for current element from underlying yielder, and returns either Next with yielded element and new state value, or Done to halt the yielder.

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 yielder: Yielder(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 yielder. If the returned value is Error(error) try_fold will stop and return that error.

Examples

from_list([1, 2, 3, 4])
|> 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),
) -> Yielder(b)

Creates an yielder from a given function and accumulator.

The function is called on the accumulator and returns either Done, indicating the yielder has no more elements, or Next which contains a new element and accumulator. The element is yielded by the yielder 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]
pub fn yield(element: a, next: fn() -> Yielder(a)) -> Yielder(a)

Add a new element to the start of an yielder.

This function is for use with use expressions, to replicate the behaviour of the yield keyword found in other languages.

Examples

let yielder = {
  use <- yield(1)
  use <- yield(2)
  use <- yield(3)
  empty()
}

yielder |> to_list
// -> [1, 2, 3]
pub fn zip(
  left: Yielder(a),
  right: Yielder(b),
) -> Yielder(#(a, b))

Zips two yielders together, emitting values from both until the shorter one runs out.

Examples

from_list(["a", "b", "c"])
|> zip(range(20, 30))
|> to_list
// -> [#("a", 20), #("b", 21), #("c", 22)]
Search Document