// @flow
import type { HKT2 } from './HKT'
import type { Setoid } from './Setoid'
import type { Semigroupoid } from './Semigroupoid'
import type { Semigroup } from './Semigroup'
import type { Monoid } from './Monoid'
import type { Functor } from './Functor'
import type { Contravariant } from './Contravariant'
import type { Apply } from './Apply'
import type { Applicative } from './Applicative'
import type { Chain } from './Chain'
import { HKT } from './HKT'
// The `Const` type constructor, which wraps its first type argument
// and ignores its second. That is, `Const a b` is isomorphic to `a`
// for any `b`.
//
// `Const` has some useful instances. For example, the `Applicative`
// instance allows us to collect results using a `Monoid` while
// ignoring return values.
class IsConst {}
export type ConstV = A; // eslint-disable-line no-unused-vars
export type Const = HKT2;
export type ConstF = HKT;
export function inj(a: ConstV): Const {
return ((a: any): Const)
}
export function prj(a: Const): ConstV {
return ((a: any): ConstV)
}
export function compose(x: Const, y: Const): Const {
return ((y: any): Const)
}
export function map(f: (a: A) => B, fa: Const): Const {
return ((fa: any): Const)
}
export function contramap(f: (b: B) => A, fa: Const): Const {
return ((fa: any): Const)
}
export function getSetoid(setoid: Setoid): Setoid> {
return {
equals(x: Const, y: Const): boolean {
return setoid.equals(prj(x), prj(y))
}
}
}
export function getSemigroup(semigroup: Semigroup): Semigroup> {
return {
concat(x: Const, y: Const): Const {
return inj(semigroup.concat(prj(x), prj(y)))
}
}
}
export function getMonoid(monoid: Monoid): Monoid> {
const { concat } = getSemigroup(monoid)
const empty: Const = inj(monoid.empty())
return {
concat,
empty(): Const {
return empty
}
}
}
export function getApply(semigroup: Semigroup): Apply> {
return {
map,
ap(fab: Const B>, fa: Const): Const {
const x = prj(fab)
const y = prj(fa)
return inj(semigroup.concat(x, y))
}
}
}
export function getApplicative(monoid: Monoid): Applicative> {
const { map, ap } = getApply(monoid)
return {
map,
ap,
of(b: B): Const { // eslint-disable-line no-unused-vars
return inj(monoid.empty())
}
}
}
export function getChain(semigroup: Semigroup): Chain> {
const { map, ap } = getApply(semigroup)
return {
map,
ap,
chain(f: (a: A) => Const, fa: Const): Const {
return ((fa: any): Const)
}
}
}
if (false) { // eslint-disable-line
({
compose,
map,
contramap
}: Functor &
Contravariant &
Semigroupoid)
}