@dillonkearns/elm-graphql
Version:
<img src="https://cdn.jsdelivr.net/gh/martimatix/logo-graphqelm/logo.svg" alt="dillonearns/elm-graphql logo" width="40%" align="right">
79 lines (57 loc) • 2.19 kB
Flow
// @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<F, G> {} // eslint-disable-line no-unused-vars
export function prj<F, G, A>(fga: HKT<IsCompose<F, G>, A>): HKT<F, HKT<G, A>> {
return ((fga: any): HKT<F, HKT<G, A>>)
}
export function inj<F, G, A>(fga: HKT<F, HKT<G, A>>): HKT<IsCompose<F, G>, A> {
return ((fga: any): HKT<IsCompose<F, G>, A>)
}
export function composeFunctor<F, G>(f: Functor<F>, g: Functor<G>): Functor<IsCompose<F, G>> {
function map<A, B>(h: (a: A) => B, fga: HKT<IsCompose<F, G>, A>): HKT<IsCompose<F, G>, B> {
return inj(f.map(ga => g.map(h, ga), prj(fga)))
}
return {
map
}
}
export function composeApplicative<F, G>(f: Applicative<F>, g: Applicative<G>): Applicative<IsCompose<F, G>> {
const { map } = composeFunctor(f, g)
function ap<A, B>(fgab: HKT<IsCompose<F, G>, (a: A) => B>, fga: HKT<IsCompose<F, G>, A>): HKT<IsCompose<F, G>, B> {
return inj(f.ap(f.map(h => ga => g.ap(h, ga), prj(fgab)), prj(fga)))
}
function of<A>(a: A): HKT<IsCompose<F, G>, A> {
return inj(f.of(g.of(a)))
}
return {
map,
ap,
of
}
}
export function composeFoldable<F1, F2>(f1: Foldable<F1>, f2: Foldable<F2>): Foldable<IsCompose<F1, F2>> {
function reduce<A, B>(f: (b: B, a: A) => B, b: B, fa: HKT<IsCompose<F1, F2>, A>): B {
return f1.reduce((a, gb) => f2.reduce(f, a, gb), b, prj(fa))
}
return {
reduce
}
}
export function composeTraversable<T1, T2>(t1: Traversable<T1>, t2: Traversable<T2>): Traversable<IsCompose<T1, T2>> {
function traverse<F, A, B>(applicative: Applicative<F>, f: (a: A) => HKT<F, B>, ta: HKT<IsCompose<T1, T2>, A>): HKT<F, HKT<IsCompose<T1, T2>, 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
}
}