use crate::prelude::*;
pub trait Monad<A: Clone>: Applicative<A> {
type Monad<B: Clone>: Monad<B, Monad<A> = Self>;
fn bind<B: Clone, F: FnOnce(A) -> Self::Monad<B> + Clone>(self, f: F) -> Self::Monad<B>;
#[inline(always)]
fn join<Flat: Clone, MFlat: Monad<Flat, Monad<MFlat> = Self> + Clone>(self) -> MFlat
where
Self: Sized + Monad<MFlat, Monad<Flat> = MFlat>,
{
self.bind::<Flat, _>(core::convert::identity::<MFlat>)
}
#[inline(always)]
#[must_use]
fn seq(self, other: Self) -> Self
where
Self: Sized,
{
other
}
}
#[inline(always)]
pub fn bind<A: Clone, B: Clone, MA: Monad<A>, F: FnOnce(A) -> MA::Monad<B> + Clone>(
ma: MA,
f: F,
) -> MA::Monad<B> {
ma.bind(f)
}
#[inline(always)]
pub fn join<MMA: Monad<MA, Monad<A> = MA>, MA: Monad<A, Monad<MA> = MMA> + Clone, A: Clone>(
mma: MMA,
) -> MA {
mma.join()
}
#[inline(always)]
#[allow(clippy::missing_const_for_fn)]
pub fn seq<MA: Monad<A>, A: Clone>(a: MA, b: MA) -> MA {
a.seq(b)
}