// @flow import type { Functor } from './Functor' import type { Applicative } from './Applicative' import type { Foldable } from './Foldable' import type { Traversable } from './Traversable' /* Functor, Applicative, Foldable, and Traversable are all closed under composition (Monad is not) */ import { HKT } from './HKT' class IsCompose {} // eslint-disable-line no-unused-vars export function prj(fga: HKT, A>): HKT> { return ((fga: any): HKT>) } export function inj(fga: HKT>): HKT, A> { return ((fga: any): HKT, A>) } export function composeFunctor(f: Functor, g: Functor): Functor> { function map(h: (a: A) => B, fga: HKT, A>): HKT, B> { return inj(f.map(ga => g.map(h, ga), prj(fga))) } return { map } } export function composeApplicative(f: Applicative, g: Applicative): Applicative> { const { map } = composeFunctor(f, g) function ap(fgab: HKT, (a: A) => B>, fga: HKT, A>): HKT, B> { return inj(f.ap(f.map(h => ga => g.ap(h, ga), prj(fgab)), prj(fga))) } function of(a: A): HKT, A> { return inj(f.of(g.of(a))) } return { map, ap, of } } export function composeFoldable(f1: Foldable, f2: Foldable): Foldable> { function reduce(f: (b: B, a: A) => B, b: B, fa: HKT, A>): B { return f1.reduce((a, gb) => f2.reduce(f, a, gb), b, prj(fa)) } return { reduce } } export function composeTraversable(t1: Traversable, t2: Traversable): Traversable> { function traverse(applicative: Applicative, f: (a: A) => HKT, ta: HKT, A>): HKT, B>> { return applicative.map(inj, t1.traverse(applicative, t2a => t2.traverse(applicative, f, t2a), prj(ta))) } return { map: composeFunctor(t1, t2).map, reduce: composeFoldable(t1, t2).reduce, traverse } }