import type { Apply2, ApplyMin } from './Apply' import type { MonoidalFunctorMin } from './MonoidalFunctor' import type { Pure, Pure2, PureFn, PureMin } from './Pure' import type { Unit, Unit2, UnitMin } from './Unit' import { Apply, getApplyComposition } from './Apply' import { flow } from './function' import * as HKT from './HKT' import { getMonoidalFunctorComposition } from './MonoidalFunctor' /** * A lax monoidal endofunctor * * `Applicative` is isomorphic to `MonoidalFunctor` */ export interface Applicative extends Apply, Unit, Pure {} export type ApplicativeMin = | (ApplyMin & (PureMin | UnitMin)) | (ApplyMin & PureMin & UnitMin) | (MonoidalFunctorMin & PureMin) | MonoidalFunctorMin export function Applicative(F: ApplicativeMin): Applicative { const ApplyF = Apply(F) if ('pure' in F) { return HKT.instance>({ ...ApplyF, pure: F.pure, unit: () => F.pure(undefined) }) } else { return HKT.instance>({ ...ApplyF, pure: (a) => F.map_(F.unit(), () => a), unit: F.unit }) } } export interface Applicative2 extends Apply2, Unit2, Pure2 {} export function getApplicativeComposition( F: Applicative, G: Applicative ): Applicative2 { return HKT.instance>({ ...getApplyComposition(F, G), ...getMonoidalFunctorComposition(F, G), pure: flow(G.pure, F.pure) }) } export function pureF(F: ApplicativeMin): PureFn { if ('pure' in F) { return F.pure } else { return (a) => F.map_(F.unit(), () => a) } }