aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml21
-rw-r--r--rebar.config11
-rw-r--r--src/gleam/iterator.gleam140
-rw-r--r--src/gleam_iterator.app.src14
-rw-r--r--test/gleam/iterator_test.gleam0
5 files changed, 178 insertions, 8 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..6afde08
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,21 @@
+name: test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1.0.0
+ - uses: gleam-lang/setup-erlang@v1.0.0
+ with:
+ otp-version: 22.1
+ - uses: gleam-lang/setup-gleam@v1.0.1
+ with:
+ gleam-version: 0.5.0-rc1
+ - run: rebar3 install_deps
+ - run: rebar3 eunit
diff --git a/rebar.config b/rebar.config
index 87742d1..3f8f69d 100644
--- a/rebar.config
+++ b/rebar.config
@@ -2,14 +2,9 @@
{src_dirs, ["src", "gen/src"]}.
{profiles, [
- {test, [
- {pre_hooks, [{compile, "gleam build ."}]},
- {src_dirs, ["src", "test", "gen/src", "gen/test"]}
- ]},
-
- {dev, [
- {pre_hooks, [{compile, "gleam build ."}]}
- ]}
+ {test, [{src_dirs, ["src", "test", "gen/src", "gen/test"]}]}
]}.
+{project_plugins, [rebar_gleam]}.
+
{deps, []}.
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam
new file mode 100644
index 0000000..53b80d3
--- /dev/null
+++ b/src/gleam/iterator.gleam
@@ -0,0 +1,140 @@
+import gleam/list
+
+// Internal private representation of an Iterator
+
+enum Action(element) {
+ // Improper dancing in the middle of the street
+ // Improper dancing in the middle of the street
+ // Improper dancing in the middle of the street
+ // Somebody better notify the chief of police
+ Stop
+ Continue(element, fn() -> Action(element))
+ // 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 fn identity(x) {
+ x
+}
+
+// Public API for iteration
+
+pub enum Step(element, acc) {
+ Next(element, acc)
+ Done
+}
+
+// Creating Iterators
+
+fn do_unfold(initial, f) {
+ fn() {
+ case f(initial) {
+ Next(x, acc) -> Continue(x, do_unfold(acc, f))
+ Done -> Stop
+ }
+ }
+}
+
+// TODO: test
+// TODO: document
+pub fn unfold(from initial: acc, with f: fn(acc) -> Step(element, acc)) -> Iterator(element) {
+ opaque(do_unfold(initial, f))
+}
+
+// TODO: test
+// TODO: document
+pub fn repeatedly(f: fn() -> element) -> Iterator(element) {
+ unfold(Nil, fn(acc) { Next(f(), acc) })
+}
+
+// TODO: test
+// TODO: document
+pub fn repeat(x: element) -> Iterator(element) {
+ repeatedly(fn() { x })
+}
+
+// TODO: test
+// TODO: document
+pub fn from_list(list: List(element)) -> Iterator(element) {
+ 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)
+ Stop -> initial
+ }
+}
+
+// TODO: test
+// TODO: document
+pub fn fold(over iterator: Iterator(e), from initial: acc, with f: fn(e, acc) -> acc) -> acc {
+ do_fold(unopaque(iterator), initial, f)
+}
+
+// TODO: test
+// TODO: document
+// For side effects
+pub fn run(iterator) -> Nil {
+ fold(iterator, Nil, fn(_, acc) { acc })
+}
+
+// TODO: test
+// TODO: document
+pub fn to_list(iterator: Iterator(element)) -> List(element) {
+ iterator
+ |> fold(_, [], fn(e, acc) { [e | acc] })
+ |> list.reverse
+}
+
+// Transforming Iterators
+
+fn do_map(iterator, f) {
+ fn() {
+ case iterator() {
+ Continue(e, iterator) -> Continue(f(e), do_map(iterator, f))
+ Stop -> Stop
+ }
+ }
+}
+
+// TODO: test
+// TODO: document
+pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) {
+ opaque(do_map(unopaque(iterator), f))
+}
+
+fn do_filter(iterator, predicate) {
+ fn() {
+ case iterator() {
+ Continue(e, iterator) -> case predicate(e) {
+ True -> Continue(e, iterator)
+ False -> do_filter(iterator, predicate)()
+ }
+ Stop -> Stop
+ }
+ }
+}
+
+// TODO: test
+// TODO: document
+pub fn filter(iterator: Iterator(a), for predicate: fn(a) -> Bool) -> Iterator(a) {
+ opaque(do_filter(unopaque(iterator), predicate))
+}
diff --git a/src/gleam_iterator.app.src b/src/gleam_iterator.app.src
new file mode 100644
index 0000000..98defca
--- /dev/null
+++ b/src/gleam_iterator.app.src
@@ -0,0 +1,14 @@
+{application, gleam_iterator,
+ [{description, "A Gleam program"},
+ {vsn, "1.0.0"},
+ {registered, []},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {licenses, ["Apache 2.0"]},
+ {links, []}
+]}.
diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/gleam/iterator_test.gleam