import type { ApplicativeExceptMin } from './ApplicativeExcept' import type { Either } from './Either' import type { MonadMin } from './Monad' import { pureF } from './Applicative' import { ApplicativeExcept } from './ApplicativeExcept' import { bindF_ } from './Bind' import * as E from './Either' import * as HKT from './HKT' import { Monad } from './Monad' export interface MonadExcept extends Monad, ApplicativeExcept { readonly refail: RefailFn } export type MonadExceptMin = MonadMin & ApplicativeExceptMin export function MonadExcept(F: MonadExceptMin): MonadExcept { const MonadF = Monad(F) const ApplicativeExceptF = ApplicativeExcept(F) return HKT.instance>({ ...MonadF, ...ApplicativeExceptF, refail: MonadF.bind(E.match(ApplicativeExceptF.fail, ApplicativeExceptF.pure)) }) } export interface RefailFn { ( fa: HKT.Kind, A>> ): HKT.Kind, A> } export function refailF(F: MonadExceptMin): RefailFn { const bind_ = bindF_(F) const pure = pureF(F) return (fa) => bind_(fa, E.match(F.fail, pure)) }