/** * @since 0.24.0 */ import { dual, identity } from "effect/Function" import type { Kind, TypeClass, TypeLambda } from "effect/HKT" import type { Coproduct } from "./Coproduct.js" import type { Monad } from "./Monad.js" import type { Monoid } from "./Monoid.js" /** * @category type class * @since 0.24.0 */ export interface Foldable extends TypeClass { readonly reduce: { (b: B, f: (b: B, a: A) => B): (self: Kind) => B (self: Kind, b: B, f: (b: B, a: A) => B): B } } /** * Returns a default ternary `reduce` composition. * * @since 0.24.0 */ export const reduceComposition = ( F: Foldable, G: Foldable ) => ( self: Kind>, b: B, f: (b: B, a: A) => B ): B => F.reduce(self, b, (b, ga) => G.reduce(ga, b, f)) /** * @since 0.24.0 */ export const toArrayMap = ( F: Foldable ): { (f: (a: A) => B): (self: Kind) => Array (self: Kind, f: (a: A) => B): Array } => dual( 2, (self: Kind, f: (a: A) => B): Array => F.reduce(self, [], (out: Array, a) => [...out, f(a)]) ) /** * @since 0.24.0 */ export const toArray = ( F: Foldable ): (self: Kind) => Array => toArrayMap(F)(identity) /** * @since 0.24.0 */ export const combineMap = (F: Foldable) => (M: Monoid): { (f: (a: A) => M): (self: Kind) => M (self: Kind, f: (a: A) => M): M } => dual( 2, (self: Kind, f: (a: A) => M): M => F.reduce(self, M.empty, (m, a) => M.combine(m, f(a))) ) /** * @since 0.24.0 */ export const reduceKind = (F: Foldable) => (G: Monad): { ( b: B, f: (b: B, a: A) => Kind ): (self: Kind) => Kind ( self: Kind, b: B, f: (b: B, a: A) => Kind ): Kind } => dual(3, ( self: Kind, b: B, f: (b: B, a: A) => Kind ): Kind => F.reduce( self, G.of(b), (gb: Kind, a) => G.flatMap(gb, (b) => f(b, a)) )) /** * @since 0.24.0 */ export const coproductMapKind = (F: Foldable) => (G: Coproduct): { ( f: (a: A) => Kind ): (self: Kind) => Kind ( self: Kind, f: (a: A) => Kind ): Kind } => dual(2, ( self: Kind, f: (a: A) => Kind ): Kind => F.reduce(self, G.zero(), (gb: Kind, a) => G.coproduct(gb, f(a))))