diff options
author | Louis Pilfold <louis@lpil.uk> | 2020-05-22 12:11:31 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2020-05-26 19:19:29 +0100 |
commit | 3fefc3fc5efccbedacbf16a52b9531efa0d9ab30 (patch) | |
tree | 4d6e5424af42e1e9f1eca5b3c0b3cf8eee162d1f | |
parent | c8d393929ae233e80684b9063b3aaeae97291811 (diff) | |
download | gleam_stdlib-3fefc3fc5efccbedacbf16a52b9531efa0d9ab30.tar.gz gleam_stdlib-3fefc3fc5efccbedacbf16a52b9531efa0d9ab30.zip |
Update iterator for next Gleam
-rw-r--r-- | src/gleam/iterator.gleam | 101 | ||||
-rw-r--r-- | test/gleam/iterator_test.gleam | 53 |
2 files changed, 76 insertions, 78 deletions
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index c139140..8a4410d 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -1,7 +1,6 @@ import gleam/list // Internal private representation of an Iterator - type Action(element) { // Improper dancing in the middle of the street // Improper dancing in the middle of the street @@ -9,33 +8,25 @@ type Action(element) { // Somebody better notify the chief of police Stop Continue(element, fn() -> Action(element)) - // Yes! } +// Yes! // Wrapper to hide the internal representation - -pub external type Iterator(element); - -// TODO: remove once we have opaque type wrappers -external fn opaque(fn() -> Action(element)) -> Iterator(element) - = "gleam@iterator" "identity" - -external fn unopaque(Iterator(element)) -> fn() -> Action(element) - = "gleam@iterator" "identity" +pub opaque type Iterator(element) { + Iterator(thunk: fn() -> Action(element)) +} pub fn identity(x) { x } // Public API for iteration - pub type Step(element, acc) { Next(element, acc) Done } // Creating Iterators - fn do_unfold(initial, f) { fn() { case f(initial) { @@ -46,10 +37,13 @@ fn do_unfold(initial, f) { } // TODO: document -pub fn unfold(from initial: acc, with f: fn(acc) -> Step(element, acc)) -> Iterator(element) { +pub fn unfold( + from initial: acc, + with f: fn(acc) -> Step(element, acc), +) -> Iterator(element) { initial - |> do_unfold(_, f) - |> opaque + |> do_unfold(f) + |> Iterator } // TODO: test @@ -65,16 +59,18 @@ pub fn repeat(x: element) -> Iterator(element) { // TODO: document pub fn from_list(list: List(element)) -> Iterator(element) { - unfold(list, fn(acc) { - case acc { - [] -> Done - [head | tail] -> Next(head, tail) - } - }) + unfold( + list, + fn(acc) { + case acc { + [] -> Done + [head, ..tail] -> Next(head, tail) + } + }, + ) } // Consuming Iterators - fn do_fold(iterator, initial, f) { case iterator() { Continue(element, iterator) -> do_fold(iterator, f(element, initial), f) @@ -83,10 +79,13 @@ fn do_fold(iterator, initial, f) { } // TODO: document -pub fn fold(over iterator: Iterator(e), from initial: acc, with f: fn(e, acc) -> acc) -> acc { - iterator - |> unopaque - |> do_fold(_, initial, f) +pub fn fold( + over iterator: Iterator(e), + from initial: acc, + with f: fn(e, acc) -> acc, +) -> acc { + iterator.thunk + |> do_fold(initial, f) } // TODO: test @@ -99,14 +98,17 @@ pub fn run(iterator) -> Nil { // TODO: document pub fn to_list(iterator: Iterator(element)) -> List(element) { iterator - |> fold(_, [], fn(e, acc) { [e | acc] }) + |> fold([], fn(e, acc) { [e, ..acc] }) |> list.reverse } fn do_take(iterator, desired, acc) { case desired > 0 { True -> case iterator() { - Continue(element, iterator) -> do_take(iterator, desired - 1, [element | acc]) + Continue( + element, + iterator, + ) -> do_take(iterator, desired - 1, [element, ..acc]) Stop -> acc } False -> acc @@ -115,9 +117,8 @@ fn do_take(iterator, desired, acc) { // TODO: document pub fn take(from iterator: Iterator(e), up_to desired: Int) -> List(e) { - iterator - |> unopaque - |> do_take(_, desired, []) + iterator.thunk + |> do_take(desired, []) |> list.reverse } @@ -133,14 +134,12 @@ fn do_drop(iterator, desired) { // TODO: document pub fn drop(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) { - iterator - |> unopaque - |> do_drop(_, desired) - |> opaque + iterator.thunk + |> do_drop(desired) + |> Iterator } // Transforming Iterators - fn do_map(iterator, f) { fn() { case iterator() { @@ -152,10 +151,9 @@ fn do_map(iterator, f) { // TODO: document pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) { - iterator - |> unopaque - |> do_map(_, f) - |> opaque + iterator.thunk + |> do_map(f) + |> Iterator } fn do_filter(iterator, predicate) { @@ -171,11 +169,13 @@ fn do_filter(iterator, predicate) { } // TODO: document -pub fn filter(iterator: Iterator(a), for predicate: fn(a) -> Bool) -> Iterator(a) { - iterator - |> unopaque - |> do_filter(_, predicate) - |> opaque +pub fn filter( + iterator: Iterator(a), + for predicate: fn(a) -> Bool, +) -> Iterator(a) { + iterator.thunk + |> do_filter(predicate) + |> Iterator } fn do_cycle(next: fn() -> Action(a), reset: fn() -> Action(a)) { @@ -189,10 +189,9 @@ fn do_cycle(next: fn() -> Action(a), reset: fn() -> Action(a)) { // TODO: document pub fn cycle(iterator: Iterator(a)) -> Iterator(a) { - let iterator = iterator |> unopaque - iterator - |> do_cycle(_, iterator) - |> opaque + iterator.thunk + |> do_cycle(iterator.thunk) + |> Iterator } fn do_range(current, limit, inc) -> fn() -> Action(Int) { @@ -209,5 +208,5 @@ pub fn range(from start, to stop) -> Iterator(Int) { False -> -1 } |> do_range(start, stop, _) - |> opaque + |> Iterator } diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam index 936621e..ec1eac3 100644 --- a/test/gleam/iterator_test.gleam +++ b/test/gleam/iterator_test.gleam @@ -1,16 +1,15 @@ -import gleam/expect +import gleam/should import gleam/iterator import gleam/list // TODO: Property tests - // a |> from_list |> to_list == a pub fn to_from_list_test() { let test = fn(subject) { subject |> iterator.from_list |> iterator.to_list - |> expect.equal(_, subject) + |> should.equal(subject) } test([]) @@ -19,13 +18,13 @@ pub fn to_from_list_test() { test([1, 2, 4, 8]) } -// a |> from_list |> take(_, n) == a |> list.take(_, n) +// a |> from_list |> take(n) == a |> list.take(_, n) pub fn take_test() { let test = fn(n, subject) { subject |> iterator.from_list - |> iterator.take(_, n) - |> expect.equal(_, list.take(subject, n)) + |> iterator.take(n) + |> should.equal(list.take(subject, n)) } test(0, []) @@ -40,30 +39,30 @@ pub fn take_test() { test(22, [0, 1, 2, 3, 4]) } -// a |> from_list |> fold(_, a, f) == a |> list.fold(_, a, f) +// a |> from_list |> fold(a, f) == a |> list.fold(_, a, f) pub fn fold_test() { let test = fn(subject, acc, f) { subject |> iterator.from_list - |> iterator.fold(_, acc, f) - |> expect.equal(_, list.fold(subject, acc, f)) + |> iterator.fold(acc, f) + |> should.equal(list.fold(subject, acc, f)) } - let f = fn(e, acc) { [e | acc] } + let f = fn(e, acc) { [e, ..acc] } test([], [], f) test([1], [], f) test([1, 2, 3], [], f) test([1, 2, 3, 4, 5, 6, 7, 8], [], f) } -// a |> from_list |> map(_, f) |> to_list == a |> list.map(_, f) +// a |> from_list |> map(f) |> to_list == a |> list.map(_, f) pub fn map_test() { let test = fn(subject, f) { subject |> iterator.from_list - |> iterator.map(_, f) + |> iterator.map(f) |> iterator.to_list - |> expect.equal(_, list.map(subject, f)) + |> should.equal(list.map(subject, f)) } let f = fn(e) { e * 2 } @@ -73,14 +72,14 @@ pub fn map_test() { test([1, 2, 3, 4, 5, 6, 7, 8], f) } -// a |> from_list |> filter(_, f) |> to_list == a |> list.filter(_, f) +// a |> from_list |> filter(f) |> to_list == a |> list.filter(_, f) pub fn filter_test() { let test = fn(subject, f) { subject |> iterator.from_list - |> iterator.filter(_, f) + |> iterator.filter(f) |> iterator.to_list - |> expect.equal(_, list.filter(subject, f)) + |> should.equal(list.filter(subject, f)) } let even = fn(x) { x % 2 == 0 } @@ -96,33 +95,33 @@ pub fn filter_test() { pub fn repeat_test() { 1 |> iterator.repeat - |> iterator.take(_, 5) - |> expect.equal(_, [1, 1, 1, 1, 1]) + |> iterator.take(5) + |> should.equal([1, 1, 1, 1, 1]) } pub fn cycle_test() { [1, 2, 3] |> iterator.from_list |> iterator.cycle - |> iterator.take(_, 9) - |> expect.equal(_, [1, 2, 3, 1, 2, 3, 1, 2, 3]) + |> iterator.take(9) + |> should.equal([1, 2, 3, 1, 2, 3, 1, 2, 3]) } pub fn unfold_test() { iterator.unfold(2, fn(acc) { iterator.Next(acc, acc * 2) }) - |> iterator.take(_, 5) - |> expect.equal(_, [2, 4, 8, 16, 32]) + |> iterator.take(5) + |> should.equal([2, 4, 8, 16, 32]) iterator.unfold(2, fn(_) { iterator.Done }) - |> iterator.take(_, 5) - |> expect.equal(_, []) + |> iterator.take(5) + |> should.equal([]) } pub fn range_test() { let test = fn(a, b, expected) { iterator.range(a, b) |> iterator.to_list - |> expect.equal(_, expected) + |> should.equal(expected) } test(0, 0, []) @@ -135,7 +134,7 @@ pub fn range_test() { pub fn drop_test() { iterator.range(0, 10) - |> iterator.drop(_, 5) + |> iterator.drop(5) |> iterator.to_list - |> expect.equal(_, [5, 6, 7, 8, 9]) + |> should.equal([5, 6, 7, 8, 9]) } |