import type { ApplicativeMin } from './Applicative' import type { Either } from './Either' import type { Fail, FailMin } from './Fail' import type { Option } from './Option' import { Applicative, pureF } from './Applicative' import * as E from './Either' import { flow } from './function' import * as HKT from './HKT' import * as O from './Option' export interface ApplicativeExcept extends Applicative, Fail { readonly catchAll_: CatchAllFn_ readonly catchAll: CatchAllFn readonly catchSome_: CatchSomeFn_ readonly catchSome: CatchSomeFn readonly attempt: AttemptFn } export type ApplicativeExceptMin = ApplicativeMin & FailMin & { readonly catchAll_: CatchAllFn_ } export function ApplicativeExcept( F: ApplicativeExceptMin ): ApplicativeExcept { const ApplicativeF = Applicative(F) const catchSome_ = catchSomeF_(F) return HKT.instance>({ ...ApplicativeF, catchAll_: F.catchAll_, catchAll: (f) => (fa) => F.catchAll_(fa, f), catchSome_, catchSome: (f) => (fa) => catchSome_(fa, f), attempt: attemptF(F), fail: F.fail }) } export interface CatchAllFn_ { ( fa: HKT.Kind, f: ( e: HKT.OrFix<'E', C, E> ) => HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A1 > ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, E1, A | A1 > } export interface CatchAllFn { ( f: (e: HKT.OrFix<'E', C, E>) => HKT.Kind ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, E1, A | A1 > } export interface CatchSomeFn_ { ( fa: HKT.Kind, f: ( e: HKT.OrFix<'E', C, E> ) => Option< HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A1 > > ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A | A1 > } export function catchSomeF_(F: ApplicativeExceptMin): CatchSomeFn_ { return (fa, f) => F.catchAll_( fa, flow( f, O.getOrElse(() => fa) ) ) } export interface CatchSomeFn { ( f: (e: HKT.OrFix<'E', C, E>) => Option> ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A | A1 > } export function catchSomeF(F: ApplicativeExceptMin): CatchSomeFn { return (f) => (fa) => F.catchAll_( fa, flow( f, O.getOrElse(() => fa) ) ) } export interface AttemptFn { (fa: HKT.Kind): HKT.Kind< F, C, N, K, Q, W, X, I, S, R, never, Either, A> > } export function attemptF(F: ApplicativeExceptMin): AttemptFn { const pure = pureF(F) return (fa) => F.catchAll_(F.map_(fa, E.Right), (e) => pure(E.Left(e))) }