diff options
author | Robert Attard <robert.attard@mail.mcgill.ca> | 2022-07-27 09:46:26 -0400 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2022-07-27 18:37:46 +0100 |
commit | 4b3b5d972650e6d7580aed479fd0404c37371cf6 (patch) | |
tree | 416cc36bbb7eecb46da8fcfd89c60cb790268b14 | |
parent | 2d991bd9439ba837ee238972f3f97d762513bcbc (diff) | |
download | gleam_stdlib-4b3b5d972650e6d7580aed479fd0404c37371cf6.tar.gz gleam_stdlib-4b3b5d972650e6d7580aed479fd0404c37371cf6.zip |
inclusive list.range and iterator.range
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | src/gleam/iterator.gleam | 43 | ||||
-rw-r--r-- | src/gleam/list.gleam | 8 | ||||
-rw-r--r-- | test/gleam/iterator_test.gleam | 16 | ||||
-rw-r--r-- | test/gleam/list_test.gleam | 12 |
5 files changed, 47 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index b5adc01..d471cee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ranges when compiled to JavaScript. - Fixed a bug where the `list` module's `contains`, `any`, and `all` could exhaust the stack when compiling to JavaScript. +- `list.range` and `iterator.range` return values are now inclusive of both start and end bounds. ## v0.22.1 - 2022-06-27 diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index 92729a1..6290b05 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -1,6 +1,8 @@ +import gleam/int import gleam/list import gleam/map.{Map} import gleam/option.{None, Option, Some} +import gleam/order // Internal private representation of an Iterator type Action(element) { @@ -447,29 +449,40 @@ pub fn cycle(iterator: Iterator(a)) -> Iterator(a) { /// /// ```gleam /// > range(from: 1, to: 5) |> to_list -/// [1, 2, 3, 4] +/// [1, 2, 3, 4, 5] /// /// > range(from: 1, to: -2) |> to_list -/// [1, 0, -1] +/// [1, 0, -1, -2] /// /// > range(from: 0, to: 0) |> to_list -/// [] +/// [0] /// ``` /// pub fn range(from start: Int, to stop: Int) -> Iterator(Int) { - let increment = case start < stop { - True -> 1 - False -> -1 - } - - let next_step = fn(current) { - case current == stop { - True -> Done - False -> Next(current, current + increment) - } + case int.compare(start, stop) { + order.Eq -> once(fn() { start }) + order.Gt -> + unfold( + from: start, + with: fn(current) { + case current < stop { + False -> Next(current, current - 1) + True -> Done + } + }, + ) + + order.Lt -> + unfold( + from: start, + with: fn(current) { + case current > stop { + False -> Next(current, current + 1) + True -> Done + } + }, + ) } - - unfold(start, next_step) } fn do_find(continuation: fn() -> Action(a), f: fn(a) -> Bool) -> Result(a, Nil) { diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam index 1a9d5ce..a46278a 100644 --- a/src/gleam/list.gleam +++ b/src/gleam/list.gleam @@ -1038,13 +1038,13 @@ pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) { /// /// ```gleam /// > range(0, 0) -/// [] +/// [0] /// /// > range(0, 5) -/// [0, 1, 2, 3, 4] +/// [0, 1, 2, 3, 4, 5] /// /// > range(1, -5) -/// [1, 0, -1, -2, -3, -4] +/// [1, 0, -1, -2, -3, -4, -5] /// ``` /// pub fn range(from start: Int, to stop: Int) -> List(Int) { @@ -1053,7 +1053,7 @@ pub fn range(from start: Int, to stop: Int) -> List(Int) { fn tail_recursive_range(start: Int, stop: Int, acc: List(Int)) -> List(Int) { case int.compare(start, stop) { - order.Eq -> reverse(acc) + order.Eq -> reverse([stop, ..acc]) order.Gt -> tail_recursive_range(start - 1, stop, [start, ..acc]) order.Lt -> tail_recursive_range(start + 1, stop, [start, ..acc]) } diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam index 8f035d9..976e209 100644 --- a/test/gleam/iterator_test.gleam +++ b/test/gleam/iterator_test.gleam @@ -222,19 +222,19 @@ pub fn range_test() { |> should.equal(expected) } - test(0, 0, []) - test(1, 1, []) - test(-1, -1, []) - test(0, 1, [0]) - test(0, 5, [0, 1, 2, 3, 4]) - test(1, -5, [1, 0, -1, -2, -3, -4]) + test(0, 0, [0]) + test(1, 1, [1]) + test(-1, -1, [-1]) + test(0, 1, [0, 1]) + test(0, 5, [0, 1, 2, 3, 4, 5]) + test(1, -5, [1, 0, -1, -2, -3, -4, -5]) } pub fn drop_test() { iterator.range(0, 10) |> iterator.drop(5) |> iterator.to_list - |> should.equal([5, 6, 7, 8, 9]) + |> should.equal([5, 6, 7, 8, 9, 10]) } type Cat { @@ -392,7 +392,7 @@ pub fn last_test() { iterator.range(1, 10) |> iterator.last - |> should.equal(Ok(9)) + |> should.equal(Ok(10)) } pub fn empty_test() { diff --git a/test/gleam/list_test.gleam b/test/gleam/list_test.gleam index 566aa94..1ea4f42 100644 --- a/test/gleam/list_test.gleam +++ b/test/gleam/list_test.gleam @@ -472,22 +472,22 @@ pub fn index_map_test() { pub fn range_test() { list.range(0, 0) - |> should.equal([]) + |> should.equal([0]) list.range(1, 1) - |> should.equal([]) + |> should.equal([1]) list.range(-1, -1) - |> should.equal([]) + |> should.equal([-1]) list.range(0, 1) - |> should.equal([0]) + |> should.equal([0, 1]) list.range(0, 5) - |> should.equal([0, 1, 2, 3, 4]) + |> should.equal([0, 1, 2, 3, 4, 5]) list.range(1, -5) - |> should.equal([1, 0, -1, -2, -3, -4]) + |> should.equal([1, 0, -1, -2, -3, -4, -5]) // This should not overflow the stack list.range(1, 100_000) |