// @flow import type { Either } from './Either' import type { Maybe } from './Maybe' import type { PTraversal } from './PTraversal' import type { Applicative } from './Applicative' import { HKT } from './HKT' import * as either from './Either' import * as maybe from './Maybe' import { id } from './Identity' export interface POptional { getOrModify(s: S): Either, set(b: B, s: S): T } export type Optional = POptional; function toMaybe(e: Either): Maybe { return either.either(maybe.toNothing, maybe.of, e) } export function getOption(stab: POptional, s: S): Maybe { return toMaybe(stab.getOrModify(s)) } export function modify(optional: POptional, f: (a: A) => B, s: S): T { return either.either( id, a => optional.set(f(a), s), optional.getOrModify(s) ) } /** join two POptional with the same target */ export function choice(optional1: POptional, optional2: POptional): POptional, Either, A, B> { return { getOrModify(s: Either): Either, A> { return either.either( s1 => either.leftMap(either.left, optional1.getOrModify(s1)), s2 => either.leftMap(either.right, optional2.getOrModify(s2)), s ) }, set(b: B, s: Either): Either { return either.bimap(s1 => optional1.set(b, s1), s2 => optional2.set(b, s2), s) } } } export function asTraversal(optional: POptional): PTraversal { return { modifyF(applicative: Applicative, f: (a: A) => HKT, s: S): HKT { return either.either( applicative.of, a => applicative.map(b => optional.set(b, s), f(a)), optional.getOrModify(s) ) } } } export function composeOptional(abcd: POptional, stab: POptional): POptional { return { getOrModify(s: S): Either { return either.chain( a => either.bimap( b => stab.set(b, s), id, abcd.getOrModify(a) ), stab.getOrModify(s) ) }, set(d: D, s: S): T { return modify(stab, a => abcd.set(d, a), s) } } }