metatrait 0.0.0-alpha.0

RPITIT Monads
Documentation
use either::Either;
use metatrait::{
    cat::{
        functor::*,
        instances::verbatim::Verbatim,
        morphism::*,
        util::{IsToEither, Wraps},
    },
    traits::{
        either::IntoEither,
        is::{Is, IsExt},
    },
    Impl, Trait,
};

trait Fetch {
    type T;
    type Wr: ?Sized + Map + Pure + Iterate;
    fn fetch(self) -> impl Wraps<Self::Wr, Self::T>;
}

struct BoxFetch<T>(Box<Stack<T, Self>>);

impl<T> Fetch for BoxFetch<T> {
    type T = Stack<T, Self>;
    type Wr = Verbatim;

    fn fetch(self) -> impl Wraps<Self::Wr, Self::T> {
        *self.0
    }
}

struct Stack<T, F: Fetch<T = Self>> {
    _value: T,
    next: Option<F>,
}

struct Count<F>(usize, F);

impl<F: Fetch> TraitFn for Count<F> {
    type Out = Is<usize>;
}

impl<T, F: Fetch<T = Stack<T, F>>> IterateFn<F::Wr> for Count<F> {
    fn run(self) -> impl Impl<<F::Wr as Wrap>::Wrap<IntoEither<Self, Self::Out>>> {
        self.1
            .fetch()
            .w_map(move |x: Stack<T, F>| match x.next {
                Some(f) => Either::Left(Self(self.0 + 1, f)),
                None => Either::Right(self.0 + 1),
            })
            .w_map(IsToEither)
    }
}

impl<T, F: Fetch<T = Self>> Stack<T, F> {
    fn count(self) -> impl Wraps<F::Wr, usize> {
        Trait::union(if let Some(next) = self.next {
            Either::Left(F::Wr::iterate(Count(1, next)))
        } else {
            Either::Right(F::Wr::pure(1))
        })
    }
}

fn main() {
    let stack = Stack {
        _value: "123",
        next: Some(BoxFetch(Box::new(Stack {
            _value: "456",
            next: None,
        }))),
    };
    let count = stack.count().into_that();
    println!("{count}");
}