aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gleam/iterator.gleam101
-rw-r--r--test/gleam/iterator_test.gleam53
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])
}