/* * Copyright 2022 Jakob Schneider Villumsen * * 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 reduced to a summary value, and its functions.///pubmod Reducible {////// Trait for types that can be reduced to a summary value.////// `Reducible` is like a non-empty `Foldable` and may only be implemented on non-empty data structures.///pubtraitReducible[t: Type -> Type] {////// The associated effect of the `Reducible` instance.////// The effect describes the effect of traversing the underlying data structure./// It is pure (i.e. `{}`) for immutable data structures.///typeAef[t]: Eff = {}////// Left-associative reduction of a structure./// Applies `g` to the initial element of `t` and combines it/// with the remainder of `t` using `f` going from left to right.///pubdefreduceLeftTo(f: (b, a) -> b \ ef1, g: a -> b \ ef2, t: t[a]): b \ (ef1 + ef2 + Reducible.Aef[t])////// Right-associative reduction of a structure./// Applies `g` to the initial element of `t` and combines it/// with the remainder of `t` using `f` going from right to left.///pubdefreduceRightTo(f: (a, b) -> b \ ef1, g: a -> b \ ef2, t: t[a]): b \ (ef1 + ef2 + Reducible.Aef[t])////// Left-associative reduction on `t` using `f`.///pubdefreduceLeft(f: (a, a) -> a \ ef, t: t[a]): a \ (ef + Reducible.Aef[t]) =Reducible.reduceLeftTo(f, identity, t)////// Right-associative reduction on `t` using `f`.///pubdefreduceRight(f: (a, a) -> a \ ef, t: t[a]): a \ (ef + Reducible.Aef[t]) =Reducible.reduceRightTo(f, identity, t)////// Reduce `t` using the derived `SemiGroup` instance.///pubdefreduce(t: t[a]): a \ Reducible.Aef[t] withSemiGroup[a] =Reducible.reduceLeft(SemiGroup.combine, t)////// Applies `f` to each element of `t` and combines them using the derived `SemiGroup` instance.///pubdefreduceMap(f: a -> b \ ef, t: t[a]): b \ (ef + Reducible.Aef[t]) withSemiGroup[b] =Reducible.reduceLeftTo((b, a) -> SemiGroup.combine(b, f(a)), f, t)////// 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 + Reducible.Aef[t]) =Reducible.reduceLeftTo(f, a -> f(s, a), 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 + Reducible.Aef[t]) =Reducible.reduceRightTo(f, a -> f(a, s), t)////// Alias for `reduce`.////// Reduce `t` using the derived `SemiGroup` instance.///pubdeffold(t: t[a]): a \ Reducible.Aef[t] withSemiGroup[a] =Reducible.reduceLeft(SemiGroup.combine, t)////// Returns the first element of `t`.///pubdefhead(t: t[a]): a \ Reducible.Aef[t] =Reducible.reduceLeft((acc, _) -> acc, t)////// Returns the last element of `t`.///pubdeflast(t: t[a]): a \ Reducible.Aef[t] =Reducible.reduceLeft((_, a) -> a, t)////// Returns `t` as a list without the last element.///pubdefinit(t: t[a]): List[a] \ Reducible.Aef[t] =Reducible.reduceRightTo((a, acc) -> a :: acc, _ -> Nil, t)////// Returns the tail of `t` as a list.///pubdeftail(t: t[a]): List[a] \ Reducible.Aef[t] =// NB: Builds a continuation function without the first// element that is immediately invoked to avoid `foldRight`.Reducible.reduceLeftTo((k, a) -> ks -> k(a :: ks), _ -> identity, t)(Nil)////// Returns the reverse of `t` as a list.///pubdefreverse(t: t[a]): List[a] \ Reducible.Aef[t] =Reducible.foldLeft((acc, a) -> a :: acc, Nil, t)////// Returns the number of elements in `t` that satisfy the predicate `f`.///pubdefcount(f: a -> Bool \ ef, t: t[a]): Int32 \ (ef + Reducible.Aef[t]) =Reducible.foldLeft((acc, a) -> if (f(a)) 1+accelseacc, 0, t)////// Returns the number of elements in `t`.///pubdeflength(t: t[a]): Int32 \ Reducible.Aef[t] =Reducible.foldLeft((acc, _) -> 1+acc, 0, t)////// Returns the sum of all elements in `t`.///pubdefsum(t: t[Int32]): Int32 \ Reducible.Aef[t] =Reducible.foldLeft((acc, a) -> a+acc, 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 + Reducible.Aef[t]) =Reducible.foldLeft((acc, a) -> f(a) +acc, 0, t)////// Returns `true` if and only if at least one element in `t` satisfies the predicate `f`.///pubdefexists(f: a -> Bool \ ef, t: t[a]): Bool \ (ef + Reducible.Aef[t]) =Reducible.foldLeft((acc, a) -> f(a) oracc, false, t)////// Returns `true` if and only if all elements in `t` satisfy the predicate `f`.///pubdefforAll(f: a -> Bool \ ef, t: t[a]): Bool \ (ef + Reducible.Aef[t]) =Reducible.foldLeft((acc, a) -> f(a) andacc, true, t)////// Applies `f` to each element in `t`.///pubdefforEach(f: a -> Unit \ ef, t: t[a]): Unit \ (ef + Reducible.Aef[t]) =Reducible.foldLeft((_, a) -> f(a), (), t)////// Alias for `findLeft`.////// Optionally returns the first element of `t` that satisfies the predicate `f` when searching from left to right.///pubdeffind(f: a -> Bool \ ef, t: t[a]): Option[a] \ (ef + Reducible.Aef[t]) =Reducible.findLeft(f, t)////// Optionally returns the first element of `t` that satisfies the predicate `f` when searching from left to right.///pubdeffindLeft(f: a -> Bool \ ef, t: t[a]): Option[a] \ (ef + Reducible.Aef[t]) =Reducible.foldLeft((acc, a) -> Option.withDefault(default = if (f(a)) Some(a) else None, acc), None, t)////// Optionally returns the first element of `t` that satisfies the predicate `f` when searching from right to left.///pubdeffindRight(f: a -> Bool \ ef, t: t[a]): Option[a] \ (ef + Reducible.Aef[t]) =Reducible.foldRight((a, acc) -> Option.withDefault(default = if (f(a)) Some(a) else None, acc), None, t)////// Returns `true` if and only if the element `a` is in `t`.///pubdefmemberOf(a: a, t: t[a]): Bool \ Reducible.Aef[t] withEq[a] =Reducible.foldLeft((acc, x) -> a==xoracc, false, t)////// Finds the smallest element of `t` according to the `Order` on `a`.///pubdefminimum(t: t[a]): a \ Reducible.Aef[t] withOrder[a] =Reducible.reduceLeft(Order.min, t)////// Finds the smallest element of `t` according to the given comparator `cmp`.///pubdefminimumBy(cmp: (a, a) -> Comparison, t: t[a]): a \ Reducible.Aef[t] =Reducible.reduceLeft(Order.minBy(cmp), t)////// Finds the largest element of `t` according to the `Order` on `a`.///pubdefmaximum(t: t[a]): a \ Reducible.Aef[t] withOrder[a] =Reducible.reduceLeft(Order.max, t)////// Finds the largest element of `t` according to the given comparator `cmp`.///pubdefmaximumBy(cmp: (a, a) -> Comparison, t: t[a]): a \ Reducible.Aef[t] =Reducible.reduceLeft(Order.maxBy(cmp), t)////// Returns `t` as a list without the longest prefix that satisfies the predicate `f`.///pubdefdropWhile(f: a -> Bool \ ef, t: t[a]): List[a] \ (ef + Reducible.Aef[t]) =defstep(acc, a) = {let (c, xs) = acc;if (candf(a)) (true, xs)else (false, a :: xs) };Reducible.foldLeft(step, (true, Nil), t) |> snd |> List.reverse////// Returns the longest prefix of `t` as a list that satisfies the predicate `f`.///pubdeftakeWhile(f: a -> Bool \ ef, t: t[a]): List[a] \ (ef + Reducible.Aef[t]) =defstep(acc, a) = {let (c, xs) = acc;if (candf(a)) (true, a :: xs)else (false, xs) };Reducible.foldLeft(step, (true, Nil), t) |> snd |> List.reverse////// Returns `t` as a list with `a` inserted between every two adjacent elements.///pubdefintersperse(a: a, t: t[a]): List[a] \ Reducible.Aef[t] =Reducible.reduceRightTo((x, acc) -> x :: a :: acc, x -> x :: Nil, t)////// Returns `t` as an array.///pubdeftoArray(rc: Region[r], t: t[a]): Array[a, r] \ (r + Reducible.Aef[t]) =letv = MutList.empty(rc);Reducible.foldLeft((_, a) -> MutList.push(a, v), (), t);MutList.toArray(rc, v)////// Returns `t` as a vector.///pubdeftoVector(t: t[a]): Vector[a] \ Reducible.Aef[t] = regionrc {letl = MutList.empty(rc);Reducible.foldLeft((_, a) -> MutList.push(a, l), (), t);MutList.toVector(l) }////// Returns `t` as a list.///pubdeftoList(t: t[a]): List[a] \ Reducible.Aef[t] =Reducible.foldRight((a, acc) -> a :: acc, Nil, t)////// Returns `t` as a map.///pubdeftoMap(t: t[(k, v)]): Map[k, v] \ Reducible.Aef[t] withOrder[k] =Reducible.foldLeft((acc, a) -> Map.insert(fst(a), snd(a), acc), Map.empty(), t)////// Returns `t` as a non-empty list.///pubdeftoNel(t: t[a]): Nel[a] \ Reducible.Aef[t] =Reducible.reduceLeftTo((acc, a) -> Nel.append(acc, Nel.Nel(a, Nil)), a -> Nel.Nel(a, Nil), t)////// Returns `t` as a set.///pubdeftoSet(t: t[a]): Set[a] \ Reducible.Aef[t] withOrder[a] =Reducible.foldLeft((acc, a) -> Set.insert(a, acc), Set.empty(), t) }////// Returns the number of elements in `t`.///pubdefsize(t: t[a]): Int32 \ Reducible.Aef[t] withReducible[t] = Reducible.length(t)}