// @flow import type { HKT2 } from './HKT' import type { Bifunctor } from './Bifunctor' import type { Monad } from './Monad' import type { Alt } from './Alt' import type { Extend } from './Extend' import type { Foldable } from './Foldable' import type { Applicative } from './Applicative' import type { Traversable } from './Traversable' import type { Semigroup } from './Semigroup' import type { MonadError } from './MonadError' import { HKT } from './HKT' import { unsafeCoerce } from './Unsafe' import { Data1 } from './Data' import { id } from './Identity' class IsEither {} export class Left extends Data1 {} export class Right extends Data1 {} export type EitherV = Left | Right; export type Either = HKT2; export type EitherF = HKT; export function inj(e: EitherV): Either { return ((e: any): Either) } export function prj(fe: Either): EitherV { return ((fe: any): EitherV) } export function left(left: L): Either { return inj(new Left(left)) } export function right(right: R): Either { return inj(new Right(right)) } export function isLeft(e: Either): boolean { return prj(e) instanceof Left } export function isRight(e: Either): boolean { return prj(e) instanceof Right } export function fromLeft(flr: Either): L { const lr = prj(flr) if (lr instanceof Right) { throw new Error('fromLeft returned a Right') } return lr.value0 } export function fromRight(flr: Either): R { const lr = prj(flr) if (lr instanceof Left) { throw new Error('fromRight returned a Left') } return lr.value0 } export function map(f: (a: A) => B, fa: Either): Either { const a = prj(fa) if (a instanceof Left) { return unsafeCoerce(a) } return right(f(a.value0)) } export function bimap(f: (a: A) => B, g: (c: C) => D, fac: Either): Either { const ac = prj(fac) if (ac instanceof Left) { return left(f(ac.value0)) } return right(g(ac.value0)) } export function leftMap(f: (l: L1) => L2, e: Either): Either { return either.bimap(f, id, e) } export function ap(fab: Either B>, fa: Either): Either { const ab = prj(fab) if (ab instanceof Left) { return unsafeCoerce(ab) } return map(ab.value0, fa) } export const of = right export function chain(f: (a: A) => Either, fa: Either): Either { const a = prj(fa) if (a instanceof Left) { return unsafeCoerce(fa) } return f(a.value0) } export function alt(fx: Either, fy: Either): Either { if (prj(fx) instanceof Left) { return fy } return fx } export function extend(f: (ea: Either) => B, ea: Either): Either { return prj(ea) instanceof Left ? unsafeCoerce(ea) : right(f(ea)) } export function reduce(f: (b: B, a: A) => B, b: B, fa: Either): B { const a = prj(fa) if (a instanceof Left) { return b } return f(b, a.value0) } export function traverse(applicative: Applicative, f: (a: A) => HKT, ta: Either): HKT> { const a = prj(ta) if (a instanceof Left) { return applicative.of(unsafeCoerce(ta)) } return applicative.map(of, f(a.value0)) } export function getMonadError(): MonadError> { return { of, map, ap, chain, throwError(e: E): Either { return left(e) }, catchError(ma: Either, handler: (e: E) => Either): Either { return either(handler, right, ma) } } } export function concat(semigroup: Semigroup): (fx: Either, fy: Either) => Either { return function concat(fx, fy) { const x = prj(fx) const y = prj(fy) if (x instanceof Right && y instanceof Right) { return right(semigroup.concat(x.value0, y.value0)) } return fx } } export function getSemigroup(semigroup: Semigroup): Semigroup> { return { concat: concat(semigroup) } } export function either(f: (l: L) => C, g: (r: R) => C, fa: Either): C { const a = prj(fa) if (a instanceof Left) { return f(a.value0) } return g(a.value0) } export class Do { static of(a: A): Do { return new Do(of(a)) } value: Either; constructor(value: Either) { this.value = value } map(f: (a: A) => B): Do { return new Do(map(f, this.value)) } chain(f: (a: A) => Either): Do { return new Do(chain(f, this.value)) } } if (false) { // eslint-disable-line ({ map, ap, of, chain, bimap, alt, extend, reduce, traverse }: Monad & Bifunctor & Alt & Extend & Foldable & Traversable) }