import type { Eq } from "@principia/prelude/Eq"; import type { Predicate, Refinement } from "../Function"; import { left, right } from "./constructors"; import { map_ } from "./functor"; import { isLeft } from "./guards"; import type { Either } from "./model"; /* * ------------------------------------------- * Either Combinators * ------------------------------------------- */ /** * orElse_ :: Either E => (E a b, (a -> b)) -> a | b */ export const orElse_ = (fa: Either, onLeft: (e: E) => Either): Either => isLeft(fa) ? onLeft(fa.left) : fa; /** * orElse :: Either E => (a -> b) -> E a b -> a | b */ export const orElse: (onLeft: (e: E) => Either) => (fa: Either) => Either = ( f ) => (fa) => orElse_(fa, f); /** * orElseEither_ :: Either E => (E a b, (a -> E c a)) -> E c (E a b) */ export const orElseEither_ = (fa: Either, onLeft: (e: E) => Either): Either> => orElse_(map_(fa, left), (e) => map_(onLeft(e), right)); /** * orElseEither :: Either E => (a -> E c a) -> E a b -> E c (E a b) */ export const orElseEither: ( onLeft: (e: E) => Either ) => (fa: Either) => Either> = (f) => (fa) => orElseEither_(fa, f); /** * filterOrElse_ :: (Either E, Bool B) => (E a b, (a -> B), (a -> c)) -> E (a | c) b */ export const filterOrElse_: { (fa: Either, refinement: Refinement, onFalse: (a: A) => G): Either; (fa: Either, predicate: Predicate, onFalse: (a: A) => G): Either; } = (fa: Either, predicate: Predicate, onFalse: (a: A) => G) => isLeft(fa) ? fa : predicate(fa.right) ? right(fa.right) : left(onFalse(fa.right)); /** * filterOrElse :: (Either E, Bool B) => ((a -> B), (a -> c)) -> E a b -> E (a | c) b */ export const filterOrElse: { (refinement: Refinement, onFalse: (a: A) => G): (fa: Either) => Either; (predicate: Predicate, onFalse: (a: A) => G): (fa: Either) => Either; } = (predicate: Predicate, onFalse: (a: A) => G) => (fa: Either) => filterOrElse_(fa, predicate, onFalse); export const elem = (E: Eq) => (a: A, fa: Either): boolean => isLeft(fa) ? false : E.equals(a)(fa.right); export const exists_: { (fa: Either, refinement: Refinement): fa is Either; (fa: Either, predicate: Predicate): fa is Either; } = (fa: Either, predicate: Predicate): fa is Either => (isLeft(fa) ? false : predicate(fa.right)); export const exists: { (refinement: Refinement): (fa: Either) => fa is Either; (predicate: Predicate): (fa: Either) => fa is Either; } = (predicate: Predicate) => (fa: Either): fa is Either => exists_(fa, predicate);