/** * @tsplus type Select */ export interface Select extends HKT.Typeclass { readonly select: ( fab: HKT.Kind B> ) => ( fa: HKT.Kind> ) => HKT.Kind } /** * @tsplus type Selective */ export type Selective = Select & Covariant & Any /** * @tsplus type SelectiveMonad */ export type SelectiveMonad = Selective & Monad /** * @tsplus type Select/Ops */ export interface SelectOps {} export const Select: SelectOps = {} /** * @tsplus static Select/Ops monad */ export function monadF(F: Monad): SelectiveMonad { const succeedF = DSL.succeedF(F) const flatMapF_ = DSL.flatMapF_(F) return HKT.instance>({ ...F, select: (fab: HKT.Kind B>) => ( fa: HKT.Kind> ): HKT.Kind => flatMapF_(fa, (either) => either.fold( (a) => F.map((g: (a: A) => B) => g(a))(fab), (b) => succeedF(b) )) }) } /** * @tsplus static Select/Ops applicative */ export function applicativeF(F: Applicative): Selective { return HKT.instance>({ ...F, select: (fab: HKT.Kind B>) => (fa: HKT.Kind>): HKT.Kind => { const both = F.both(fab)(fa) return F.map(([ea, f]: readonly [Either, (a: A) => B]) => ea.fold(f, identity))(both) } }) } /** * @tsplus static Select/Ops branchF */ export function branchF(F: Selective) { return ( left: HKT.Kind D1>, right: HKT.Kind D2> ) => ( fe: HKT.Kind> ): HKT.Kind => { const mapped = F.map((either: Either) => either.map(Either.left))(fe) const selected = F.select>( F.map((fac: (a: A) => D1) => (a: A) => Either.right(fac(a)))(left) )(mapped) return F.select(right)(selected) } } /** * @tsplus static Select/Ops ifF */ export function ifF(F: Selective) { return ( then_: HKT.Kind, else_: HKT.Kind ) => ( if_: HKT.Kind ): HKT.Kind => { const mapped = F.map( (b: boolean) => (b ? Either.left(undefined) : Either.right(undefined)) )(if_) return branchF(F)( F.map((a: A) => () => a)(then_), F.map((b: B) => () => b)(else_) )(mapped) } } /** * @tsplus static Select/Ops whenF */ export function whenF(F: Selective) { const succeedF = DSL.succeedF(F) return (act: HKT.Kind) => (if_: HKT.Kind): HKT.Kind => ifF(F)(act, succeedF(undefined))(if_) }