/* * Copyright 2021 Esben Bjerre * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Trait for types that can be folded, and its functions.///pubmod Foldable {use Applicative.{*>}////// Trait for types that can be folded.///pubtraitFoldable[t: Type -> Type] {////// The associated effect of the Foldable which represents the effect of accessing its elements.///typeAef[t]: Eff = {}////// Left-associative fold of a structure./// Applies `f` to a start value `s` and all elements in `t` going from left to right.///pubdeffoldLeft(f: (b, a) -> b \ ef, s: b, t: t[a]): b \ (ef + Foldable.Aef[t])////// Right-associative fold of a structure./// Applies `f` to a start value `s` and all elements in `t` going from right to left.///pubdeffoldRight(f: (a, b) -> b \ ef, s: b, t: t[a]): b \ (ef + Foldable.Aef[t])////// Returns the number of elements in `t`.///pubdeflength(t: t[a]): Int32 \ Foldable.Aef[t] =Foldable.foldLeft((acc, _) -> acc+1, 0, t)////// Returns the number of elements in `t` that satisfy the predicate `f`.///pubdefcount(f: a -> Bool \ ef, t: t[a]): Int32 \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> if (f(x)) acc+1elseacc, 0, t)////// Returns the sum of all elements in `t`.///pubdefsum(t: t[Int32]): Int32 \ Foldable.Aef[t] =Foldable.foldLeft((+), 0, t)////// Returns the sum of all elements in `t` according to the function `f`.///pubdefsumWith(f: a -> Int32 \ ef, t: t[a]): Int32 \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> acc+f(x), 0, t)////// Returns `true` if and only if at least one element in `t` satisfies the predicate `f`.////// Returns `false` if `t` is empty.///pubdefexists(f: a -> Bool \ ef, t: t[a]): Bool \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> accorf(x), false, t)////// Returns `true` if and only if all elements in `t` satisfy the predicate `f`.////// Returns `true` if `t` is empty.///pubdefforAll(f: a -> Bool \ ef, t: t[a]): Bool \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> accandf(x), true, t)////// Optionally returns the first element of `t`.////// Returns `None` if `t` is empty.///pubdefhead(t: t[a]): Option[a] \ Foldable.Aef[t] =Foldable.foldLeft( (acc, x) -> matchacc {case Some(_) => acccase None => Some(x) }, None,t )////// Optionally returns the last element of `t`.////// Returns `None` if `t` is empty.///pubdeflast(t: t[a]): Option[a] \ Foldable.Aef[t] =Foldable.foldLeft((_, x) -> Some(x), None, t)////// Optionally returns the first element of `t` that satisfies the predicate `f` when searching from left to right.////// Returns `None` if `t` is empty.///pubdeffindLeft(f: a -> Bool \ ef, t: t[a]): Option[a] \ (ef + Foldable.Aef[t]) =Foldable.foldLeft( (acc, x) -> matchacc {case Some(_) => acccase None => if (f(x)) Some(x) else None }, None,t )////// Optionally returns the first element of `t` that satisfies the predicate `f` when searching from right to left.////// Returns `None` if `t` is empty.///pubdeffindRight(f: a -> Bool, t: t[a]): Option[a] \ Foldable.Aef[t] =Foldable.foldRight((x, acc) -> Option.withDefault(default = if (f(x)) Some(x) else None, acc), None, t)////// Returns the result of mapping each element and combining the results.///pubdeffoldMap(f: a -> b \ ef, t: t[a]): b \ (ef + Foldable.Aef[t]) withMonoid[b] =Foldable.foldLeft((acc, x) -> Monoid.combine(acc, f(x)), Monoid.empty(), t)////// Returns true if and only if `t` is empty.///pubdefisEmpty(t: t[a]): Bool \ Foldable.Aef[t] =Foldable.foldLeft((_, _) -> false, true, t)////// Returns true if and only if `t` is non-empty.///pubdefnonEmpty(t: t[a]): Bool \ Foldable.Aef[t] = notFoldable.isEmpty(t)////// Returns `true` if and only if the element `x` is in `t`.///pubdefmemberOf(x: a, t: t[a]): Bool \ Foldable.Aef[t] withEq[a] =Foldable.foldLeft((acc, y) -> accorx==y, false, t)////// Optionally finds the smallest element of `t` according to the `Order` on `a`.////// Returns `None` if `t` is empty.///pubdefminimum(t: t[a]): Option[a] \ Foldable.Aef[t] withOrder[a] =Foldable.reduceLeft(Order.min, t)////// Optionally finds the smallest element of `t` according to the given comparator `cmp`.////// Returns `None` if `t` is empty.///pubdefminimumBy(cmp: (a, a) -> Comparison, t: t[a]): Option[a] \ Foldable.Aef[t] =Foldable.reduceLeft(Order.minBy(cmp), t)////// Optionally finds the largest element of `t` according to the `Order` on `a`.////// Returns `None` if `t` is empty.///pubdefmaximum(t: t[a]): Option[a] \ Foldable.Aef[t] withOrder[a] =Foldable.reduceLeft(Order.max, t)////// Optionally finds the largest element of `t` according to the given comparator `cmp`.////// Returns `None` if `t` is empty.///pubdefmaximumBy(cmp: (a, a) -> Comparison, t: t[a]): Option[a] \ Foldable.Aef[t] =Foldable.reduceLeft(Order.maxBy(cmp), t)////// Optionally applies `f` to all elements in `t` going from left to right until a single value is obtained.////// Returns `None` if `t` is empty.///pubdefreduceLeft(f: (a, a) -> a \ ef, t: t[a]): Option[a] \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> Some(Option.foldLeft((z, v) -> f(v, z), x, acc)), None, t)////// Optionally applies `f` to all elements in `t` going from right to left until a single value is obtained.////// Returns `None` if `t` is empty.///pubdefreduceRight(f: (a, a) -> a \ ef, t: t[a]): Option[a] \ (ef + Foldable.Aef[t]) =Foldable.foldRight((x, acc) -> Some(Option.foldLeft((v, z) -> f(v, z), x, acc)), None, t)////// Returns `t` as a chain.///pubdeftoChain(t: t[a]): Chain[a] \ Foldable.Aef[t] =Foldable.foldRight((x, acc) -> Chain.cons(x, acc), Chain.empty(), t)////// Returns `t` as an immutable list.///pubdeftoList(t: t[a]): List[a] \ Foldable.Aef[t] =Foldable.foldRight((x, acc) -> x :: acc, Nil, t)////// Returns `t` as an array.///pubdeftoArray(rc: Region[r], t: t[a]): Array[a, r] \ (r + Foldable.Aef[t]) = regionrc2 {letl = MutList.empty(rc2);Foldable.forEach(a -> MutList.push(a, l), t);MutList.toArray(rc, l) }////// Returns `t` as a vector.///pubdeftoVector(t: t[a]): Vector[a] \ Foldable.Aef[t] = regionrc {letl = MutList.empty(rc);Foldable.forEach(a -> MutList.push(a, l), t);MutList.toVector(l) }////// Returns `t` as a set.///pubdeftoSet(t: t[a]): Set[a] \ Foldable.Aef[t] withOrder[a] =Foldable.foldRight(Set.insert, Set.empty(), t)////// Returns `t` as a map.///pubdeftoMap(t: t[(k, v)]): Map[k, v] \ Foldable.Aef[t] withOrder[k] =Foldable.foldRight((x, acc) -> let (k, v) = x; Map.insert(k, v, acc), Map.empty(), t)////// Returns a map with elements of `s` as keys and `f` applied as values.///pubdeftoMapWith(f: a -> b, s: t[a]): Map[a, b] \ Foldable.Aef[t] withOrder[a] =Foldable.foldRight((x, acc) -> Map.insert(x, f(x), acc), Map.empty(), s)////// Optionally returns `t` as a non empty chain.///pubdeftoNec(t: t[a]): Option[Nec[a]] \ Foldable.Aef[t] =Foldable.toChain(t) |> Chain.toNec////// Optionally returns `t` as a non empty list.///pubdeftoNel(t: t[a]): Option[Nel[a]] \ Foldable.Aef[t] =Foldable.toList(t) |> List.toNel////// Returns `t` without the longest prefix that satisfies the predicate `f`.////// Returns an immutable list.///pubdefdropWhile(f: a -> Bool, t: t[a]): List[a] \ Foldable.Aef[t] =Foldable.foldLeft( (acc, x) -> {let (c, tail) = acc;if (candf(x)) (true, tail)else (false, x :: tail) }, (true, Nil),t ) |> snd |> List.reverse////// Returns the longest prefix of `t` that satisfies the predicate `f`.////// Returns an immutable list.///pubdeftakeWhile(f: a -> Bool, t: t[a]): List[a] \ Foldable.Aef[t] =Foldable.foldRight((x, acc) -> if (f(x)) x :: accelse Nil, Nil, t)////// Returns an immutable list of all the elements in `t` that satisfy the predicate `f`.///pubdeffilter(f: a -> Bool \ ef, t: t[a]): List[a] \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((acc, x) -> if (f(x)) x :: accelseacc, Nil, t) |> List.reverse////// Applies `f` to each element in `t`.///pubdefforEach(f: a -> Unit \ ef, t: t[a]): Unit \ (ef + Foldable.Aef[t]) =Foldable.foldLeft((_, x) -> f(x), (), t)// Acknowledgement: `foldLeftM` and `foldRightM` are derived from Haskell's Data.Foldable.// Because they use CPS, the implementations work for both strict and lazy languages.// Counterintuitively `foldLeftM` uses a right-fold and `foldRighM` uses a left-fold// but the "direction of travel" is observably correct.////// A monadic version of `foldLeft`.////// Applies the monadic `f` to a start value `s` and all elements in `t` going/// from left to right.///pubdeffoldLeftM(f: (b, a) -> m[b] \ ef, s: b, t: t[a]): m[b] \ (ef + Foldable.Aef[t]) withMonad[m] =letf1 = (x, acc) -> z -> Monad.flatMap(acc, f(z, x));s |> Foldable.foldRight(f1, x1 -> checked_ecast(Applicative.point(x1)), t)////// A monadic version of `foldRight`.////// Applies the monadic `f` to a start value `s` and all elements in `t` going/// from right to left.///pubdeffoldRightM(f: (a, b) -> m[b] \ ef, s: b, t: t[a]): m[b] \ (ef + Foldable.Aef[t]) withMonad[m] =letf1 = (k, x) -> z -> Monad.flatMap(k, f(x, z));s |> Foldable.foldLeft(f1, x1 -> checked_ecast(Applicative.point(x1)), t)////// A monadic version of `forEach`.////// Apply `f` to every value in `t`. `f` is applied for its monadic effect,/// the answer it produces is discarded.///pubdefforEachM(f: a -> m[b] \ ef, t: t[a]): m[Unit] \ (ef + Foldable.Aef[t]) withMonad[m] =use Applicative.{point, *>};Foldable.foldLeftM((acc, a) -> f(a) *> point(acc), (), t)////// Returns the concatenation of the string representation/// of each element in `t` with `sep` inserted between each element.///pubdefjoin(sep: String, t: t[a]): String \ Foldable.Aef[t] withToString[a] =Foldable.joinWith(ToString.toString, sep, t)////// Returns the concatenation of the string representation/// of each element in `t` according to `f` with `sep` inserted between each element.///pubdefjoinWith(f: a -> String \ ef, sep: String, t: t[a]): String \ (ef + Foldable.Aef[t]) = regionrc {use StringBuilder.append;letlastSep = String.length(sep);letsb = StringBuilder.empty(rc);t |> Foldable.forEach(x -> { append(f(x), sb); append(sep, sb) });StringBuilder.toString(sb) |> String.dropRight(lastSep) } }////// Returns the result of applying `combine` to all the elements in `t`, using `empty` as the initial value.///pubdeffold(t: t[a]): a \ Foldable.Aef[t] withFoldable[t], Monoid[a] =Foldable.foldLeft(Monoid.combine, Monoid.empty(), t)////// Returns the number of elements in `t`.///pubdefsize(t: t[a]): Int32 \ Foldable.Aef[t] withFoldable[t] = Foldable.length(t)}