aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Attard <robert.attard@mail.mcgill.ca>2021-04-13 10:04:17 -0400
committerLouis Pilfold <louis@lpil.uk>2021-04-14 21:23:32 +0100
commit53471ea469a5ce92a500194405a121237de5d131 (patch)
tree7af335b2afebb9098e58560367c5362de6adf86b
parentfb129be0608b54412f5a70faefff5903acd5d014 (diff)
downloadgleam_stdlib-53471ea469a5ce92a500194405a121237de5d131.tar.gz
gleam_stdlib-53471ea469a5ce92a500194405a121237de5d131.zip
add list.scan
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/gleam/list.gleam30
-rw-r--r--test/gleam/list_test.gleam23
3 files changed, 54 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d0cc1c..57a3f4c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,7 @@
functions and their typed equivalents `typed_tuple3`, `typed_tuple4`,
`typed_tuple5`, `typed_tuple6`.
- The `list` module gains the `drop_while`, `map_fold`, `take_while`, `reduce`,
- `chunk` and `sized_chunk` functions.
+ `chunk`, `sized_chunk` and `scan` functions.
- The `iterator` module gains the `index`, `iterate`, `zip`, `scan`,
`take_while`, `drop_while`, `chunk`, `sized_chunk`, `intersperse`, `reduce`, `any` and `all` functions.
- Breaking change in `iterator.take`. Now it returns an iterator instead of a list.
diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam
index dc03ec1..9f88063 100644
--- a/src/gleam/list.gleam
+++ b/src/gleam/list.gleam
@@ -1401,3 +1401,33 @@ pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) {
|> Ok
}
}
+
+fn do_scan(
+ list: List(a),
+ accumulator: b,
+ accumulated: List(b),
+ fun: fn(a, b) -> b,
+) -> List(b) {
+ case list {
+ [] -> reverse(accumulated)
+ [x, ..xs] -> {
+ let next = fun(x, accumulator)
+ do_scan(xs, next, [next, ..accumulated], fun)
+ }
+ }
+}
+
+/// Similar to `fold`, but yields the state of the accumulator at each stage.
+///
+/// ## Examples
+///
+/// > scan(over: [1, 2, 3], from: 100, with: fn(i, acc) { acc + i })
+/// [101, 103, 106]
+///
+pub fn scan(
+ over list: List(a),
+ from initial: b,
+ with fun: fn(a, b) -> b,
+) -> List(b) {
+ do_scan(list, initial, [], fun)
+}
diff --git a/test/gleam/list_test.gleam b/test/gleam/list_test.gleam
index bf93203..572812c 100644
--- a/test/gleam/list_test.gleam
+++ b/test/gleam/list_test.gleam
@@ -622,3 +622,26 @@ pub fn reduce_test() {
|> list.reduce(with: fn(x, y) { x + y })
|> should.equal(Ok(15))
}
+
+pub fn scan_test() {
+ []
+ |> list.scan(from: 0, with: fn(i, acc) { i + acc })
+ |> should.equal([])
+
+ [1, 2, 3, 4]
+ |> list.scan(from: 0, with: fn(i, acc) { 2 * i + acc })
+ |> should.equal([2, 6, 12, 20])
+
+ [1, 2, 3, 4]
+ |> list.scan(
+ from: "",
+ with: fn(i, acc) {
+ case int.is_even(i) {
+ True -> "Even"
+ False -> "Odd"
+ }
+ |> string.append(acc, _)
+ },
+ )
+ |> should.equal(["Odd", "OddEven", "OddEvenOdd", "OddEvenOddEven"])
+}