/* * Copyright 2021 Jakob Schneider Villumsen, Stephen Tetley * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Type of lazy iterators scoped to a region, and its functions.///pubmod Iterator {use Step.{Ans, Skip, Done}////// Type of lazy iterators scoped to a region.///pubenumIterator[a: Type, ef: Eff, r: Region] {case Iterator(Region[r], Unit -> Iterator.Step[a] \ { r, ef }) }////// Type of steps of an iterator.////// This is an expanded version of the `Option` type./// `Ans` is the answer at an intermediate stage of iteration./// `Done` signals that iteration is complete./// `Skip` is essentially an implementation detail. It allows us/// to define `filter` and similar functions that "wither" Iterators/// without recursively running through the Iterator.///pubenumStep[a] {case Ans(a)case Skipcase Done }////// Returns an iterator built with the stepper function `f`.////// `f` is expected to encapsulate a stateful resource.////// `f` should return `Some(a)` to signal a new element `a`.////// `f` should return `None` to signal the end of the iterator.///pubdefunfoldWithIter(rc: Region[r], f: Unit -> Option[a] \ ef): Iterator[a, ef, r] =letf1 = () -> matchf() {case Some(a) => Ans(a)case None => Done };letiterF = () -> checked_ecast(f1()); Iterator(rc, iterF)////// Build an iterator by applying `f` to the seed value `st`.////// `f` should return `Some(a, st1)` to signal a new element `a` and a new seed value `st1`.////// `f` should return `None` to signal the end of the iterator.///pubdefunfold(rc: Region[r], f: s -> Option[(a, s)] \ ef, st: s): Iterator[a, ef + r, r] \ r =letstate = Ref.fresh(rc, st);letf1 = () -> matchf(Ref.get(state)) {case None => Donecase Some((a, st1)) => Ref.put(st1, state); Ans(a) };letiterF = () -> checked_ecast(f1()); Iterator(rc, iterF)////// Build an iterator by applying `f` to the initial value `x`.////// `f` should return `Some(a1)` to signal a new element `a1` (which also becomes the next input to `f`).////// `f` should return `None` to signal the end of the iterator.///pubdefiterate(rc: Region[r], f: a -> Option[a] \ ef, x: a): Iterator[a, ef + r, r] \ r =letstate = Ref.fresh(rc, x);letf1 = () -> matchf(Ref.get(state)) {case None => Donecase Some(a1) => Ref.put(a1, state); Ans(a1) };letiterF = () -> checked_ecast(f1()); Iterator(rc, iterF)////// Returns an empty iterator.///pubdefempty(rc: Region[r]): Iterator[a, r, r] =letf = _ -> checked_ecast(Done); Iterator(rc, f)////// Returns an iterator containing only a single element, `x`.///pubdefsingleton(rc: Region[r], x: a): Iterator[a, r, r] \ r =repeat(rc, 1, x)////// Returns `Some(x)` if `iter` is not empty. Returns `None` otherwise.////// Consumes the head element of `iter`.///pubdefnext(iter: Iterator[a, ef, r]): Option[a] \ { ef, r } =let Iterator(_, iterF) = iter;defloop() = matchiterF() {case Ans(a) => Some(a)case Skip => loop()case Done => None };loop()////// Returns an iterator of all integers between `b` (inclusive) and `e` (exclusive).////// Returns an empty iterator if `b >= e`.///pubdefrange(rc: Region[r], b: Int32, e: Int32): Iterator[Int32, r, r] \ r =letpos = Ref.fresh(rc, b);if (e<=b)empty(rc)else {letiterF = () -> match (Ref.get(pos)) {caseiifi<e => Ref.put(i+1, pos); Ans(i)case_ => Done }; Iterator(rc, iterF) }////// Returns an iterator over an iterable with the element `x` repeated `n` times.////// Returns an empty iterator if `n < 0`.///pubdefrepeat(rc: Region[r], n: Int32, x: a): Iterator[a, r, r] \ r =letix = Ref.fresh(rc, n);letiterF = () -> {leti = Ref.get(ix);if (i<1) Doneelse {Ref.put(i-1, ix); Ans(x) } }; Iterator(rc, iterF)////// Returns the sum of all elements in the iterator `iter`.////// Consumes the entire iterator.///pubdefsum(iter: Iterator[Int32, ef, r]): Int32 \ { ef, r } =foldLeft((+), 0, iter)////// Returns the sum of all elements in the iterator `iter` according to the function `f`.////// Consumes the entire iterator.///pubdefsumWith(f: a -> Int32 \ ef2, iter: Iterator[a, ef1, r]): Int32 \ { ef1, ef2, r } =foldLeft((acc, x) -> acc+f(x), 0, iter)////// Returns the contents of `iter` as an array.////// Consumes the entire iterator.///pubdeftoArray(rc: Region[r1], iter: Iterator[a, ef, r2]): Array[a, r1] \ { ef, r2, r1 } = regionrc1 {letm = MutList.empty(rc1);forEach(a -> MutList.push(a, m), iter);MutList.toArray(rc, m) }////// Returns the contents of `iter` as an array.////// Consumes the entire iterator.///pubdeftoVector(iter: Iterator[a, ef, r]): Vector[a] \ { ef, r } = regionrc {letm = MutList.empty(rc);forEach(a -> MutList.push(a, m), iter);MutList.toVector(m) }////// Returns the contents of `iter` as a list.////// Consumes the entire iterator.///pubdeftoList(iter: Iterator[a, ef, r]): List[a] \ { ef, r } =foldRight((a, acc) -> a :: acc, Nil, iter)////// Returns the contents of `iter` as a chain.////// Consumes the entire iterator.///pubdeftoChain(iter: Iterator[a, ef, r]): Chain[a] \ { ef, r } =foldLeft(Chain.snoc, Chain.empty(), iter)////// Returns the contents of `iter` as a map.////// Consumes the entire iterator.///pubdeftoMap(iter: Iterator[(k, v), ef, r]): Map[k, v] \ { ef, r } withOrder[k] =foldLeft((acc, a) -> (match (k, v) -> Map.insert(k, v, acc))(a), Map.empty(), iter)////// Returns the contents of `iter` as a `Some(Nel)` if `iter` is not empty. Returns None otherwise.////// Consumes the entire iterator.///pubdeftoNel(iter: Iterator[a, ef, r]): Option[Nel[a]] \ { ef, r } =toList(iter) |> List.toNel////// Returns the contents of `iter` as a Nec.////// Consumes the entire iterator.///pubdeftoNec(iter: Iterator[a, ef, r]): Option[Nec[a]] \ { ef, r } = matchnext(iter) {case Some(a) => foldLeft(Nec.snoc, Nec.singleton(a), iter) |> Somecase None => None }////// Returns the contents of `iter` as a set. Consumes the entire iterator.///pubdeftoSet(iter: Iterator[a, ef, r]): Set[a] \ { ef, r } withOrder[a] =foldLeft((acc, a) -> Set.insert(a, acc), Set.empty(), iter)////// Applies `f` to every element of `iter`.////// Consumes the entire iterator.///pubdefforEach(f: a -> Unit \ ef2, iter: Iterator[a, ef1, r]): Unit \ { ef1, ef2, r } =let Iterator(_, iterF) = iter;defloop() = matchiterF() {case Skip => loop()case Ans(a) => f(a); loop()case Done => () };loop()////// Applies `f` to every element of `iter` along with that element's index.////// Consumes the entire iterator.///pubdefforEachWithIndex(f: (Int32, a) -> Unit \ ef2, iter: Iterator[a, ef1, r]): Unit \ { ef1, ef2, r } =let Iterator(_, iterF) = iter;defloop(i) = matchiterF() {case Skip => loop(i)case Ans(a) => f(i, a); loop(i+1)case Done => () };loop(0)////// Returns an iterator with every element of the iterator `iter` that/// satisfies the predicate `f`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdeffilter(f: a -> Bool \ ef2, iter: Iterator[a, ef1, r]): Iterator[a, ef1 + ef2, r] =let Iterator(rc, iterF) = iter;letstep = x -> matchx {case Ans(a) => if (f(a)) Ans(a) else Skipcase Skip => Skipcase Done => Done };letiterF1 = () -> step(iterF()); Iterator(rc, iterF1)////// Returns an iterator with every `f` lazily applied to each element in `iter`.////// Does *not* consume any elements from the iterator.///pubdefmap(f: a -> b \ ef2, iter: Iterator[a, ef1, r]): Iterator[b, ef1 + ef2, r] =let Iterator(rc, iterF) = iter;letstep = x -> matchx {case Ans(a) => Ans(f(a))case Skip => Skipcase Done => Done };letiterF1 = () -> { letx = iterF(); step(x) }; Iterator(rc, iterF1)////// Returns an iterator with every `f` lazily applied to each element in `iter`/// together with its index.////// Does *not* consume any elements from the iterator.///pubdefmapWithIndex(f: (Int32, a) -> b \ ef2, iter: Iterator[a, ef1, r]): Iterator[b, ef1 + ef2, r] \ r =let Iterator(rc, iterF) = iter;letix = Ref.fresh(rc, 0);letstep = x -> matchx {case Ans(a) => { leti = Ref.get(ix); Ref.put(i+1, ix); Ans(f(i, a)) }case Skip => Skipcase Done => Done };letiterF1 = () -> { letx = iterF(); step(x) }; Iterator(rc, iterF1)////// Returns an iterator with every occurrence of `src` replaced by `dst` in `iter`.////// Does *not* consume any elements from the iterator.///pubdefreplace(src: {src = a}, dst: {dst = a}, iter: Iterator[a, ef, r]): Iterator[a, ef, r] withEq[a] =map(a -> if (a==src#src) dst#dst elsea, iter)////// Returns `iterB` appended to (the end of) `iterA`.////// Does *not* consume any elements from either iterator.////// The original iterators `iterA` and `iterB` should *not* be reused.///pubdefappend(iter1: Iterator[a, ef1, r], iter2: Iterator[a, ef2, r]): Iterator[a, ef1 + ef2, r] =let Iterator(rc, iter1F) = iter1;let Iterator(_, iter2F) = iter2;defloop2(x) = matchx {case Ans(a) => Ans(a)case Skip => loop2(iter2F())case Done => Done };defloop1(x) = matchx {case Ans(a) => Ans(a)case Skip => loop1(iter1F())case Done => loop2(iter2F()) };letiter3F = () -> loop1(iter1F()); Iterator(rc, iter3F)////// Returns an iterator where the element at index `i` is `(a, b)` where/// `a` is the element at index `i` in `iterA` and `b` is the element at index `i` in `iterB`.////// Does *not* consume any elements from either iterator.////// If either `iterA` or `iterB` is depleted, then no further elements are added to the resulting iterator.////// The original iterators `iterA` and `iterB` should *not* be reused.////// An iterator should *never* be zipped with itself.///pubdefzip(iterA: Iterator[a, ef1, r1], iterB: Iterator[b, ef2, r2]): Iterator[(a, b), r2 + ef1 + ef2, r1] =zipWith((a, b) -> (a, b), iterA, iterB)////// Returns an iterator where the element at index `i` is `f(a, b)` where/// `a` is the element at index `i` in `iterA` and `b` is the element at index `i` in `iterB`.////// Does *not* consume any elements from either iterator.////// If either `iterA` or `iterB` becomes depleted, then no further elements are added to the resulting list.////// The original iterators `iterA` and `iterB` should *not* be reused.////// An iterator should *never* be zipped with itself.///pubdefzipWith(f: (a, b) -> c \ ef3, iterA: Iterator[a, ef1, r1], iterB: Iterator[b, ef2, r2]): Iterator[c, r2 + ef1 + ef2 + ef3, r1] =let Iterator(rc, iter1F) = iterA;let Iterator(_, iter2F) = iterB;letstep = (l, r) -> match (l, r) {case (Ans(a), Ans(b)) => Ans(f(a, b))case (Ans(a), Skip) => zipWithGoRight(b -> f(a, b), iter2F)case (Skip, Ans(b)) => zipWithGoLeft(iter1F, a -> f(a, b))case (Skip, Skip) => Skipcase (_, _) => Done };letiter3F = () -> step(iter1F(), iter2F()); Iterator(rc, iter3F)////// Helper function for `zipWith`.///defzipWithGoLeft(iter: Unit -> Step[a] \ ef1, f: a -> c \ ef2): Step[c] \ { ef1, ef2 } = matchiter() {case Ans(a) => Ans(f(a))case Skip => zipWithGoLeft(iter, f)case Done => Done }////// Helper function for `zipWith`.///defzipWithGoRight(f: b -> c \ ef2, iter: Unit -> Step[b] \ ef1): Step[c] \ { ef1, ef2 } = matchiter() {case Ans(b) => Ans(f(b))case Skip => zipWithGoRight(f, iter)case Done => Done }////// Returns an iterator where the element at index `i` is `(a, i)` where/// `a` is the element at index `i` in `iter`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdefzipWithIndex(iter: Iterator[a, ef, r]): Iterator[(Int32, a), ef + r, r] \ r =let Iterator(rc, _) = iter;letix = Ref.fresh(rc, 0);map(x -> { leti = Ref.get(ix); Ref.put(i+1, ix); (i, x) }, iter)////// Applies `f` to a start value `s` and all elements in `iter` going from left to right.////// That is, the result is of the form: `f(...f(f(s, x1), x2)..., xn)`.////// Consumes the entire iterator.///pubdeffoldLeft(f: (b, a) -> b \ ef2, s: b, iter: Iterator[a, ef1, r]): b \ { ef1, ef2, r } =let Iterator(_, iterF) = iter;defloop(acc) = matchiterF() {case Skip => loop(acc)case Ans(a) => loop(f(acc, a))case Done => acc };loop(s)////// Applies `f` to a start value `s` and all elements in `iter` going from right to left.////// That is, the result is of the form: `f(x1, ...f(xn-1, f(xn, s))...)`.////// Consumes the entire iterator.///pubdeffoldRight(f: (a, b) -> b \ ef2, s: b, iter: Iterator[a, ef1, r]): b \ { ef1, ef2, r } =let Iterator(_, iterF) = iter;defloop(k) = matchiterF() {case Skip => loop(k)case Ans(a) => loop(ks -> k(f(a, ks)))case Done => k(s) };loop(x -> checked_ecast(x))////// Returns the result of mapping each element and combining the results.///pubdeffoldMap(f: a -> b \ ef2, iter: Iterator[a, ef1, r]): b \ { ef1, ef2, r } withMonoid[b] =foldLeft((acc, x) -> Monoid.combine(acc, f(x)), Monoid.empty(), iter)////// Applies `f` to all elements in `iter` going from left to right until a single value `v` is obtained. Returns `Some(v)`.////// That is, the result is of the form: `Some(f(...f(f(x1, x2), x3)..., xn))`////// Returns `None` if `iter` is empty.////// Consumes the entire iterator.///pubdefreduceLeft(f: (a, a) -> a \ ef2, iter: Iterator[a, ef1, r]): Option[a] \ { ef1, ef2, r } =matchnext(iter) {case Some(x) => foldLeft(f, x, iter) |> Somecase None => None }////// Returns an iterator over the results of `f`.////// If `f` returns `Ok(x)`, then the next element is `x`.////// If `f` returns `Err(e)`, then the iterator is depleted.///pubdefunfoldWithOk(rc: Region[r], f: Unit -> Result[e, a] \ ef): Iterator[a, ef, r] =letiterF = () -> Result.toOption(f());Iterator.unfoldWithIter(rc, iterF)////// Returns `iter` without the first `n` elements.////// Returns an empty iterator if `n` is larger than the number of elements in `iter`./// Returns `iter` if `n < 0`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdefdrop(n: Int32, iter: Iterator[a, ef, r]): Iterator[a, ef + r, r] \ r =let Iterator(rc, iterF) = iter;letix = Ref.fresh(rc, n);defloop() = {leti = Ref.get(ix);Ref.put(i-1, ix);matchiterF() {case Ans(a) => if (i>0) loop()else Ans(a)case Skip => loop()case Done => Done } };letiter1F = () -> loop(); Iterator(rc, iter1F)////// Returns `iter` with the first `n` elements.////// Returns `iter` if `n` is larger than the number of elements in `iter`./// Returns an empty iterator if `n < 0`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdeftake(n: Int32, iter: Iterator[a, ef, r]): Iterator[a, ef + r, r] \ r =let Iterator(rc, iterF) = iter;letix = Ref.fresh(rc, n);defloop() = {leti = Ref.get(ix);if (i<1) DoneelsematchiterF() {case Ans(a) => Ref.put(i-1, ix); Ans(a)case Skip => Skipcase Done => Done } };letiter1F = () -> loop(); Iterator(rc, iter1F)////// Returns the longest prefix of `iter` that satisfies the predicate `f`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdeftakeWhile(f: a -> Bool \ ef2, iter: Iterator[a, ef1, r]): Iterator[a, ef1 + ef2, r] =let Iterator(rc, iterF) = iter;defloop(x) = matchx {case Ans(a) => if (f(a)) Ans(a) else Donecase Skip => loop(iterF())case Done => Done };letiter1F = () -> loop(iterF()); Iterator(rc, iter1F)////// Returns `iter` without the longest prefix that satisfies the predicate `f`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdefdropWhile(f: a -> Bool \ ef2, iter: Iterator[a, ef1, r]): Iterator[a, r + ef1 + ef2, r] \ r =let Iterator(rc, iterF) = iter;letstart = Ref.fresh(rc, true);defloop() = matchiterF() {case Ans(a) =>if (Ref.get(start)) {if (f(a)) Skip else { Ref.put(false, start); Ans(a) } } else { Ans(a) }case Skip => Skipcase Done => Done };letiter1F = () -> loop(); Iterator(rc, iter1F)////// Returns the result of applying `f` to every element in `iter` and concatenating the results.////// Does *not* consume any elements from the iterator.////// Currently `f` has to generate an iterator with region `r`.///pubdefflatMap(f: a -> Iterator[b, ef2, r] \ ef3, ma: Iterator[a, ef1, r]): Iterator[b, r + ef1 + ef2 + ef3, r] \ r =let Iterator(rc, iterF) = ma;letinnerIter = Ref.fresh(rc, polymorphicEmpty(rc));letinside = Ref.fresh(rc, false);definnerLoop() = {let Iterator(_, innerF) = Ref.get(innerIter);matchinnerF() {case Ans(b) => Ans(b)case Skip => innerLoop()case Done => Done } };defouterLoop() = {if (Ref.get(inside)) {matchinnerLoop() {case Done => Ref.put(false, inside); outerLoop()caseans => ans } } else {matchiterF() {case Ans(a) =>Ref.put(true, inside);Ref.put(f(a), innerIter);outerLoop()case Skip => outerLoop()case Done => Done } } };letiter1F = () -> outerLoop(); Iterator(rc, iter1F)////// Helper for `flatMap`.////// This is a cheat to get the initial inner iterator (inside the `innerIter` reference) to/// typecheck and compile. Ideally we would use the public API function `empty` but its type/// is not general enough at the use-site when `innerIter` is re-assigned within `outerLoop`.///defpolymorphicEmpty(rc: Region[r]): Iterator[a, ef, r] =letf = _ -> checked_ecast(Done); Iterator(rc, f)////// Returns an iterator with `a` inserted between every of `iter`.////// Does *not* consume any elements from the iterator.///pubdefintersperse(sep: a, iter: Iterator[a, ef, r]): Iterator[a, ef + r, r] \ r =let Iterator(rc, _) = iter;letstart = Ref.fresh(rc, true);letstep = x ->if (Ref.get(start)) {Ref.put(false, start);singleton(rc, x) } else {cons(sep, singleton(rc, x)) };flatMap(step, iter)////// Returns the concatenation of the elements in `iter` with the elements of `sep` inserted between every two adjacent elements.////// That is, returns `b1 :: a1 ... an :: b2 :: ... bn-1 :: a1 :: ... :: an :: bn :: Nil`.////// Does *not* consume any elements from either iterator.////// The original iterators `sep` and `iter` should not be reused.///pubdefintercalate(sep: t[a], iter: Iterator[Iterator[a, ef, r], ef, r]): Iterator[a, ef + r, r] \ (r + Foldable.Aef[t]) withFoldable[t] =let Iterator(rc, _) = iter;letstart = Ref.fresh(rc, true);letsepL = Foldable.toList(sep);letstep = innerIter -> {if (Ref.get(start)) {Ref.put(false, start);innerIter } else {append(ofList(rc, sepL), innerIter) } };flatMap(step, iter)////// Helper for `intercalate`.////// Note - this is not the "best" return type. Ideally it should be `Iterator[a, r, r]` but/// then `intercalate` fails.///defofList(rc: Region[r], xs: List[a]): Iterator[a, {}, r] \ r =letls = Ref.fresh(rc, xs);letnext = () -> {match (Ref.get(ls)) {case Nil => Donecasex :: rs => Ref.put(rs, ls); Ans(x) } }; Iterator(rc, next)////// Returns the concatenation of the string representation/// of each element in `iter` with `sep` inserted between each element.////// Consumes the entire iterator.///pubdefjoin(sep: String, iter: Iterator[a, ef, r]): String \ { ef, r } withToString[a] =joinWith(ToString.toString, sep, iter)////// Returns the concatenation of the string representation/// of each element in `iter` according to `f` with `sep` inserted between each element.////// Consumes the entire iterator.///pubdefjoinWith(f: a -> String \ ef2, sep: String, iter: Iterator[a, ef1, r]): String \ { ef1, ef2, r } = regionrc {letsb = StringBuilder.empty(rc);matchnext(iter) {case Some(a) => {StringBuilder.append(f(a), sb);forEach(x -> { StringBuilder.append(sep, sb); StringBuilder.append(f(x), sb) }, iter) }case None => () };StringBuilder.toString(sb) }////// Returns an iterator with every element of the iterator `iter` that/// produces `Some(_)` the from the function `f`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdeffilterMap(f: a -> Option[b] \ ef2, iter: Iterator[a, ef1, r]): Iterator[b, ef1 + ef2, r] =let Iterator(rc, iterF) = iter;letstep = x -> matchx {case Ans(a) => match (f(a)) {case Some(a1) => Ans(a1)case None => Skip }case Skip => Skipcase Done => Done };letiterF1 = () -> step(iterF()); Iterator(rc, iterF1)////// Returns an iterator with the element `x` appended to the/// front of iterator `iter`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdefcons(x: a, iter: Iterator[a, ef, r]): Iterator[a, ef, r] \ r =let Iterator(rc, iterF) = iter;letfirst = Ref.fresh(rc, true);letf = () -> {if (Ref.get(first)) {Ref.put(false, first); Ans(x) } elseiterF() };letiter1F = () -> f(); Iterator(rc, iter1F)////// Returns the concatenation of the nested iterators in `iter`.////// Does *not* consume any elements from the iterator.////// The original iterator `iter` should *not* be reused.///pubdefflatten(iter: Iterator[Iterator[a, ef1, r], ef2, r]): Iterator[a, r + ef1 + ef2, r] \ r =flatMap(identity, iter)}