From 1643c557b5e7e5fcbaf70a689a9b9d8f74e3ee83 Mon Sep 17 00:00:00 2001 From: Marcin Puc <5671049+tranzystorek-io@users.noreply.github.com> Date: Wed, 10 Mar 2021 10:47:22 +0100 Subject: Add iterator.scan (#173) --- src/gleam/iterator.gleam | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'src') diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index 010d82a..96fd848 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -535,6 +535,22 @@ pub fn iterate( unfold(initial, fn(element) { Next(element, f(element)) }) } +fn do_scan( + continuation: fn() -> Action(element), + accumulator: acc, + f: fn(element, acc) -> acc, +) -> fn() -> Action(acc) { + fn() { + case continuation() { + Continue(el, next) -> { + let accumulated = f(el, accumulator) + Continue(accumulated, do_scan(next, accumulated, f)) + } + Stop -> Stop + } + } +} + fn do_zip( left: fn() -> Action(a), right: fn() -> Action(b), @@ -552,6 +568,26 @@ fn do_zip( } } +/// 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(el, acc) { acc + el }) |> to_list +/// [1, 3, 6, 10, 15] +/// +pub fn scan( + over iterator: Iterator(element), + from initial: acc, + with f: fn(element, acc) -> acc, +) -> Iterator(acc) { + iterator.continuation + |> do_scan(initial, f) + |> Iterator +} + /// Zips two iterators together, emitting values from both /// until the shorter one runs out. /// -- cgit v1.2.3