diff options
author | Marcin Puc <marcin.e.puc@gmail.com> | 2021-03-21 12:02:30 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2021-04-13 10:50:44 +0100 |
commit | ffeb3757f291dbff55c772b7d622e22dac79352c (patch) | |
tree | 7c301008788f1ba91d1b7d41599461a065301c3c /src | |
parent | 593eeae98d21da64d0e6a956413d3874fe762369 (diff) | |
download | gleam_stdlib-ffeb3757f291dbff55c772b7d622e22dac79352c.tar.gz gleam_stdlib-ffeb3757f291dbff55c772b7d622e22dac79352c.zip |
Add {iterator. list}.reduce
Diffstat (limited to 'src')
-rw-r--r-- | src/gleam/iterator.gleam | 35 | ||||
-rw-r--r-- | src/gleam/list.gleam | 24 |
2 files changed, 55 insertions, 4 deletions
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index f9e39bb..fa49b87 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -115,12 +115,12 @@ pub fn from_list(list: List(element)) -> Iterator(element) { // Consuming Iterators fn do_fold( continuation: fn() -> Action(e), - initial: acc, f: fn(e, acc) -> acc, + accumulator: acc, ) -> acc { case continuation() { - Continue(element, iterator) -> do_fold(iterator, f(element, initial), f) - Stop -> initial + Continue(elem, next) -> do_fold(next, f, f(elem, accumulator)) + Stop -> accumulator } } @@ -146,7 +146,7 @@ pub fn fold( with f: fn(e, acc) -> acc, ) -> acc { iterator.continuation - |> do_fold(initial, f) + |> do_fold(f, initial) } // TODO: test @@ -919,3 +919,30 @@ pub fn group( |> fold(map.new(), group_updater(key)) |> map.map_values(fn(_, group) { list.reverse(group) }) } + +/// 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(current_element, accumulator). +/// +/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator. +/// +/// ## Examples +/// +/// > from_list([]) |> reduce(fn(x, y) { x + y }) +/// Error(Nil) +/// +/// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(x, y) { x + y }) +/// Ok(15) +/// +pub fn reduce( + over iterator: Iterator(e), + with f: fn(e, e) -> e, +) -> Result(e, Nil) { + case iterator.continuation() { + Stop -> Error(Nil) + Continue(e, next) -> + do_fold(next, f, e) + |> Ok + } +} diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam index cb7d940..972da23 100644 --- a/src/gleam/list.gleam +++ b/src/gleam/list.gleam @@ -1377,3 +1377,27 @@ fn do_sized_chunk( pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) { do_sized_chunk(list, count, count, [], []) } + +/// This function acts similar to fold, but does not take an initial state. +/// Instead, it starts from the first element in the list +/// and combines it with each subsequent element in turn using the given function. +/// The function is called as fun(current_element, accumulator). +/// +/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty list. +/// +/// ## Examples +/// +/// > [] |> reduce(fn(x, y) { x + y }) +/// Error(Nil) +/// +/// > [1, 2, 3, 4, 5] |> reduce(fn(x, y) { x + y }) +/// Ok(15) +/// +pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [head, ..tail] -> + fold(tail, head, fun) + |> Ok + } +} |