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; } struct BoxFetch(Box>); impl Fetch for BoxFetch { type T = Stack; type Wr = Verbatim; fn fetch(self) -> impl Wraps { *self.0 } } struct Stack> { _value: T, next: Option, } struct Count(usize, F); impl TraitFn for Count { type Out = Is; } impl>> IterateFn for Count { fn run(self) -> impl Impl<::Wrap>> { self.1 .fetch() .w_map(move |x: Stack| match x.next { Some(f) => Either::Left(Self(self.0 + 1, f)), None => Either::Right(self.0 + 1), }) .w_map(IsToEither) } } impl> Stack { fn count(self) -> impl Wraps { 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}"); }