import type { FunctorMin } from './Functor' import type { CrossFn_ } from './Semimonoidal' import type { CrossWithFn_, SemimonoidalFunctor2, SemimonoidalFunctorMin } from './SemimonoidalFunctor' import { flow, pipe } from './function' import { getFunctorComposition } from './Functor' import * as HKT from './HKT' import { apF_, SemimonoidalFunctor } from './SemimonoidalFunctor' /** * A lax semimonoidal endofunctor * * `Apply` is isomorphic to `SemimonoidalFunctor` */ export interface Apply extends SemimonoidalFunctor { readonly ap_: ApFn_ readonly ap: ApFn readonly apl_: ApLeftFn_ readonly apl: ApLeftFn readonly apr_: ApRightFn_ readonly apr: ApRightFn } export type ApplyMin = | SemimonoidalFunctorMin | ({ readonly ap_: ApFn_ } & FunctorMin) | ({ readonly ap_: ApFn_ } & SemimonoidalFunctorMin) export function Apply(F: ApplyMin): Apply { let ap_: ApFn_ let SF: SemimonoidalFunctor if ('ap_' in F) { if ('cross_' in F || 'crossWith_' in F) { SF = SemimonoidalFunctor(F) ap_ = F.ap_ } else { SF = SemimonoidalFunctor({ map_: F.map_, crossWith_: crossWithF_(F), cross_: crossF_(F) }) ap_ = F.ap_ } } else { SF = SemimonoidalFunctor(F) ap_ = apF_(SF) } return HKT.instance>({ ...SF, ap_, ap: (fa) => (fab) => ap_(fab, fa), apl_: aplF_(F), apl: aplF(F), apr_: aprF_(F), apr: aprF(F) }) } export interface Apply2 extends SemimonoidalFunctor2 { readonly ap_: ApFn2_ readonly ap: ApFn2 } export function getApplyComposition( F: Apply, G: Apply ): Apply2 export function getApplyComposition( F: Apply>, G: Apply> ): Apply2, HKT.UHKT> { const crossWith_: Apply2, HKT.UHKT>['crossWith_'] = (fga, fgb, f) => F.crossWith_(fga, fgb, (ga, gb) => G.crossWith_(ga, gb, f)) const ap_: Apply2, HKT.UHKT>['ap_'] = ( fgab: HKT.HKT B>>, fga: HKT.HKT> ): HKT.HKT> => pipe( fgab, F.map((gab) => (ga: HKT.HKT) => G.ap_(gab, ga)), F.ap(fga) ) return HKT.instance, HKT.UHKT>>({ ...getFunctorComposition(F, G), ap_, ap: (fga) => (fgab) => ap_(fgab, fga), crossWith_, crossWith: (fgb, f) => (fga) => crossWith_(fga, fgb, f) }) } export interface ApFn { (fa: HKT.Kind): < N1 extends string, K1, Q1, W1, X1, I1, S1, R1, E1, B >( fab: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, (a: A) => B > ) => HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > } export interface ApFn_ { ( fab: HKT.Kind B>, fa: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ): HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > } export interface ApFn2 { ( fga: HKT.Kind> ): < NF1 extends string, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, NG1 extends string, KG1, QG1, WG1, XG1, IG1, SG1, RG1, EG1, B >( fgab: HKT.Kind< F, CF, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Kind< G, CG, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, (a: A) => B > > ) => HKT.Kind< F, CF, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Kind< G, CG, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > > } export interface ApFn2_ { < NF extends string, KF, QF, WF, XF, IF, SF, RF, EF, NG extends string, KG, QG, WG, XG, IG, SG, RG, EG, NF1 extends string, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, NG1 extends string, KG1, QG1, WG1, XG1, IG1, SG1, RG1, EG1, A, B >( fgab: HKT.Kind< F, TCF, NF1, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, HKT.Kind B> >, fga: HKT.Kind< F, TCF, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Kind< G, TCG, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > > ): HKT.Kind< F, TCF, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Kind< G, TCG, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > > } export function crossWithF_(F: ApplyMin): CrossWithFn_ export function crossWithF_(F: ApplyMin>): CrossWithFn_> { if ('crossWith_' in F) { return F.crossWith_ } else if ('cross_' in F) { return (fa, fb, f) => F.map_(F.cross_(fa, fb), (ab) => f(ab[0], ab[1])) } else { return (fa: HKT.HKT, fb: HKT.HKT, f: (a: A, b: B) => C) => F.ap_( F.map_(fa, (a) => (b: B) => f(a, b)), fb ) } } export function crossF_(F: ApplyMin): CrossFn_ export function crossF_(F: ApplyMin>): CrossFn_> { if ('cross_' in F) { return F.cross_ } else if ('crossWith_' in F) { return (fa, fb) => F.crossWith_(fa, fb, (a, b) => [a, b]) } else { return (fa: HKT.HKT, fb: HKT.HKT) => F.ap_( F.map_(fa, (a) => (b: B) => [a, b]), fb ) } } export interface ApLeftFn { (fb: HKT.Kind): < N extends string, K, Q, W, X, I, S, R, E, A >( fa: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A > } export interface ApLeftFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > ): HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A > } export function aplF_(A: ApplyMin): ApLeftFn_ { if ('ap_' in A) { return (left, right) => A.ap_( A.map_(left, (a) => () => a), right ) } else if ('crossWith_' in A) { return (left, right) => A.crossWith_(left, right, (a, _) => a) } else { return (left, right) => A.map_(A.cross_(left, right), ([a, _]) => a) } } export function aplF(A: ApplyMin): ApLeftFn { if ('ap_' in A) { return (right) => (left) => A.ap_( A.map_(left, (a) => () => a), right ) } else if ('crossWith_' in A) { return (right) => (left) => A.crossWith_(left, right, (a, _) => a) } else { return (right) => (left) => A.map_(A.cross_(left, right), ([a, _]) => a) } } export interface ApLeftFnComposition { < NF1 extends string, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, NG1 extends string, KG1, QG1, WG1, XG1, IG1, SG1, RG1, EG1, A, B >( fgb: HKT.Kind< F, TCF, NF1, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, HKT.Kind > ): ( fga: HKT.Kind< F, TCF, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Kind< G, TCG, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > > ) => HKT.Kind< F, TCF, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Kind< G, TCG, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A > > } export interface ApRightFn { (fb: HKT.Kind): < N extends string, K, Q, W, X, I, S, R, E, A >( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > } export interface ApRightFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > } export function aprF_(A: ApplyMin): ApRightFn_ export function aprF_(A: ApplyMin>): ApRightFn_> { if ('ap_' in A) { return (left, right) => A.ap_( A.map_(left, (_) => (b: HKT.Infer, {}, 'A', typeof right>) => b), right ) } else if ('crossWith_' in A) { return (left, right) => A.crossWith_(left, right, (_, b) => b) } else { return (left, right) => A.map_(A.cross_(left, right), ([, b]) => b) } } export function aprF(A: ApplyMin): ApRightFn export function aprF(A: ApplyMin>): ApRightFn> { if ('ap_' in A) { return (right) => (left) => A.ap_( A.map_(left, () => (b: HKT.Infer, {}, 'A', typeof right>) => b), right ) } else if ('crossWith_' in A) { return (right) => (left) => A.crossWith_(left, right, (_, b) => b) } else { return (right) => (left) => A.map_(A.cross_(left, right), ([, b]) => b) } } export interface ApRightFnComposition { < NF1 extends string, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, NG1 extends string, KG1, QG1, WG1, XG1, IG1, SG1, RG1, EG1, A, B >( fgb: HKT.Kind< F, CF, NF1, KF1, QF1, WF1, XF1, IF1, SF1, RF1, EF1, HKT.Kind > ): ( fga: HKT.Kind< F, CF, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Kind< G, CG, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > > ) => HKT.Kind< F, CF, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Kind< G, CG, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > > } export interface ApSFn { ( name: Exclude, fb: HKT.Kind ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, { [K in keyof A | BN]: K extends keyof A ? A[K] : A1 } > } export function apSF(F: Apply): ApSFn { return (name, fb) => flow( F.map((a) => (b: HKT.Infer) => Object.assign({}, a, { [name]: b })), F.ap(fb) ) } export interface ApTFn { (fb: HKT.Kind): < N extends string, K, Q, W, X, I, S, R, E, A extends ReadonlyArray >( fas: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, readonly [...A, A1] > } export function apTF(F: Apply): ApTFn { return (fb) => flow( F.map((a) => (b: HKT.Infer) => [...a, b]), F.ap(fb) ) }