use super::*;
pub trait Fail<'a, E: 'a + Send>: WeakFunctor<'a> {
fn fail<A: 'a + Send>(e: E) -> Self::F<A>;
}
pub trait MonadFail<'a, E: 'a + Send>: Monad<'a> + Fail<'a, E> {}
impl<'a, E: 'a + Send, T: Monad<'a> + Fail<'a, E>> MonadFail<'a, E> for T {}
pub trait MonadFailAny<'a>: 'a + Send {
type W<E: 'a + Send>: MonadFail<'a, E>;
type T: Monad<'a>;
fn unstuff<A: 'a + Send, E: 'a + Send>(
wa: WrapE<'a, A, E, Self>,
) -> Wrap<'a, Result<A, E>, Self::T>;
fn stuff<A: 'a + Send, E: 'a + Send>(
fa: Wrap<'a, Result<A, E>, Self::T>,
) -> WrapE<'a, A, E, Self>;
fn map_err<A: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + Send + FnOnce(E0) -> E1,
) -> WrapE<'a, A, E1, Self> {
Self::bind_err(wa, |e0| Self::fail(f(e0)))
}
fn bind_err<A: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + Send + FnOnce(E0) -> WrapE<'a, A, E1, Self>,
) -> WrapE<'a, A, E1, Self> {
Self::bind(wa, |result| match result {
Ok(a) => Self::pure(a),
Err(e0) => f(e0),
})
}
fn bind<A: 'a + Send, B: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
wa: WrapE<'a, A, E0, Self>,
f: impl 'a + Send + FnOnce(Result<A, E0>) -> WrapE<'a, B, E1, Self>,
) -> WrapE<'a, B, E1, Self> {
Self::stuff(<Self::T as Monad>::bind(Self::unstuff(wa), |result| {
Self::unstuff(f(result))
}))
}
fn join<A: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
wwa: WrapE<'a, WrapE<'a, A, E0, Self>, E1, Self>,
) -> WrapE<'a, A, Result<E0, E1>, Self> {
Self::bind(wwa, |result| match result {
Ok(wa) => Self::map_err(wa, Ok),
Err(e1) => Self::fail(Err(e1)),
})
}
fn rotate_out<A: 'a + Send, E0: 'a + Send, E1: 'a + Send>(
wa: WrapE<'a, Result<A, E1>, E0, Self>,
) -> WrapE<'a, A, Result<E1, E0>, Self> {
<Self::W<Result<E1, E0>> as Monad>::bind(Self::map_err(wa, Err), |fa| match fa {
Ok(a) => Self::pure(a),
Err(e) => Self::fail(Ok(e)),
})
}
}
pub type WrapE<'a, A, E, Fallible> = Wrap<'a, A, <Fallible as MonadFailAny<'a>>::W<E>>;
pub trait MonadFailAnyExt<'a>: MonadFailAny<'a> {
fn pure<E: 'a + Send, A: 'a + Send>(a: A) -> WrapE<'a, A, E, Self> {
<Self::W<E> as Pure>::pure(a)
}
fn fail<E: 'a + Send, A: 'a + Send>(e: E) -> WrapE<'a, A, E, Self> {
<Self::W<E> as Fail<E>>::fail(e)
}
}
impl<'a, Fallible: ?Sized + MonadFailAny<'a>> MonadFailAnyExt<'a> for Fallible {}