metatrait 0.0.0-alpha.1

RPITIT Monads
Documentation
use either::Either;

use crate::{existence::When, Impl, Trait};

use super::morphism::*;

pub trait Unwrap<Tr: ?Sized + Trait>: Wrap<Wrap<Self::Tr> = Tr> {
    type Tr: ?Sized + Trait;
}

pub trait Wrapped<Wr: ?Sized + Wrap>: Trait
where
    Wr: Wrap<Wrap<Self::Tr> = Self>,
{
    type Tr: ?Sized + Trait;
}

impl<Wr: ?Sized + Unwrap<Tr>, Tr: ?Sized + Trait> Wrapped<Wr> for Tr {
    type Tr = <Wr as Unwrap<Tr>>::Tr;
}

pub trait Wrap {
    type Wrap<Tr: ?Sized + Trait>: ?Sized + Wrapped<Self, Tr = Tr>;
}

pub trait Pure: Wrap {
    fn pure<Tr: ?Sized + Trait>(_: impl Impl<Tr>) -> impl Impl<Self::Wrap<Tr>>;
}

pub trait Map: Wrap {
    fn map<F: MapFn<In>, In: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<In>>,
        _: F,
    ) -> impl Impl<Self::Wrap<F::Out>>;
}

pub trait Map2: Wrap {
    fn map2<F: MapFn2<In0, In1>, In0: ?Sized + Trait, In1: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<In0>>,
        _: impl Impl<Self::Wrap<In1>>,
        _: F,
    ) -> impl Impl<Self::Wrap<F::Out>>;
}

pub trait Select: Wrap {
    fn select<F: SelectFn<In0, In1>, In0: ?Sized + Trait, In1: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<In0>>,
        _: impl Impl<Self::Wrap<In1>>,
        _: F,
    ) -> impl Impl<Self::Wrap<F::Out>>;
}

pub trait Flatten: Wrap {
    fn flatten<Tr: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<Self::Wrap<Tr>>>,
    ) -> impl Impl<Self::Wrap<Tr>>;
}

pub trait Iterate: Wrap {
    fn iterate<F: IterateFn<Self>>(_: F) -> impl Impl<Self::Wrap<F::Out>>;
}

pub trait ToEither: Wrap {
    type L: When;
    type R: When;
    fn either<In: ?Sized + Trait, Out: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<In>>,
    ) -> Either<(impl Impl<In>, Self::L), (impl Impl<Self::Wrap<Out>>, Self::R)>;
}

pub trait Transpose: Wrap {
    fn transpose<Wr: ?Sized + Pure + Map, Tr: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<Wr::Wrap<Tr>>>,
    ) -> impl Impl<Wr::Wrap<Self::Wrap<Tr>>>;
}

pub trait Inspect: Wrap {
    fn inspect<F: InspectFn<In, Self>, In: ?Sized + Trait>(
        _: impl Impl<Self::Wrap<In>>,
        _: F,
    ) -> impl Impl<Self::Wrap<F::Out>>;
}

pub trait Functor: Map {}

impl<Wr: ?Sized + Map> Functor for Wr {}

pub trait Applicative: Functor + Map2 + Pure {}

impl<Wr: ?Sized + Functor + Map2 + Pure> Applicative for Wr {}

pub trait Monad: Applicative + Flatten {}

impl<Wr: ?Sized + Applicative + Flatten> Monad for Wr {}

pub trait WrappedMapExt<Wr: ?Sized + Map<Wrap<Tr::Tr> = Tr>, Tr: ?Sized + Wrapped<Wr>>:
    Impl<Tr>
{
    fn w_map<F: MapFn<Tr::Tr>>(self, f: F) -> impl Impl<Wr::Wrap<F::Out>> {
        Wr::map(self, f)
    }
}

impl<Wr: ?Sized + Map<Wrap<Tr::Tr> = Tr>, Tr: ?Sized + Wrapped<Wr>, T: ?Sized + Impl<Tr>>
    WrappedMapExt<Wr, Tr> for T
{
}

pub trait WrappedFlattenExt<
    Wr: ?Sized + Flatten<Wrap<TrI> = TrO> + Flatten<Wrap<Tr> = TrI>,
    TrO: ?Sized + Wrapped<Wr, Tr = TrI>,
    TrI: ?Sized + Wrapped<Wr, Tr = Tr>,
    Tr: ?Sized + Trait,
>: Impl<TrO>
{
    fn w_flatten(self) -> impl Impl<TrI> {
        Wr::flatten::<Tr>(self)
    }
}

impl<
        Wr: ?Sized + Flatten<Wrap<TrI> = TrO> + Flatten<Wrap<Tr> = TrI>,
        TrO: ?Sized + Wrapped<Wr, Tr = TrI>,
        TrI: ?Sized + Wrapped<Wr, Tr = Tr>,
        Tr: ?Sized + Trait,
        T: Impl<TrO>,
    > WrappedFlattenExt<Wr, TrO, TrI, Tr> for T
{
}