From 4fe248f77b08c8e941b8caf8bc1aa8d675583687 Mon Sep 17 00:00:00 2001 From: timofey Date: Thu, 27 Apr 2023 08:15:42 +0000 Subject: [PATCH] `Monad::iterate` closes #9 --- src/func.rs | 27 ++++++++++++------ src/func/classes/composition.rs | 49 +++++++++++++++++++++++++++------ src/func/classes/future.rs | 20 ++++++++++++-- src/func/classes/lazy.rs | 18 ++++++++++-- src/func/classes/option.rs | 18 ++++++++++-- src/func/classes/result.rs | 18 ++++++++++-- src/func/classes/solo.rs | 18 ++++++++++-- src/func/classes/stackless.rs | 22 +++++++++++---- src/func/controlflow.rs | 47 +++++++++++++++++++++++++++---- src/std/collections/stack.rs | 2 +- src/std/tracing.rs | 21 ++++++++++++-- src/testing/counted.rs | 21 ++++++++++++-- 12 files changed, 231 insertions(+), 50 deletions(-) diff --git a/src/func.rs b/src/func.rs index 71dbf72..23c6385 100644 --- a/src/func.rs +++ b/src/func.rs @@ -21,8 +21,8 @@ pub use std::ops::ControlFlow; pub use radn_derive::{CovariantFunctor, SharedFunctor}; -pub use self::controlflow::{AIterative, AIterativeWrapped}; -use self::controlflow::{BindableMut, ControlFlowClass}; +pub use self::controlflow::{AIterative, AIterativeWrapped, Iterative, IterativeWrapped}; +use self::controlflow::{ArgumentedIterative, BindableMut, ControlFlowClass}; /// Part of Haskell's `Functor f` responsible for having `f a`. /// @@ -173,31 +173,40 @@ pub trait Monad: Applicative { where Self: 'a; - /// Simplified, [`FnMut`] version of [`Monad::iibind`]. + /// Simplified, [`FnMut`] version of [`Monad::iterate_argument`]. /// Reasoning for this method existing at all is that - /// most usecases are better modelled + /// most usecases are better modelled with [`FnMut`] + /// rather than some dedicated state type. /// - /// Note: hypothetically, you can implement [`Monad::iibind`] from [`Monad::ibind`], + /// Note: hypothetically, you can implement [`Monad::iterate_argument`] from [`Monad::iterate_mut`], /// but it's highly discouraged. - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( a: A, f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> where Self: 'a, { - Self::iibind(a, BindableMut::new(f)) + Self::iterate_argument(a, BindableMut::new(f)) } /// Kleisli category composition special case used to represent loops. /// Included for optimisation and clarity. /// Generally, [`Monad::bind`] should be enough implement it. - /// See [`classes::stackless::StacklessClass::ibind`] for a generic, though less-than ideal, blanket implementation. + /// See [`classes::stackless::StacklessClass::iterate`] for a generic, though less-than ideal, blanket implementation. /// On practice, you generally shouldn't be using [`Monad::bind`]/[`Pure::pure`]/[`Functor::fmap`] here. - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( a: A, f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> + where + Self: 'a, + { + Self::iterate(ArgumentedIterative(a, f)) + } + + /// Iteration without composition semantics of [`Monad::iterate_argument`]. + fn iterate<'a, B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> where Self: 'a; diff --git a/src/func/classes/composition.rs b/src/func/classes/composition.rs index 38e4854..b22a1b0 100644 --- a/src/func/classes/composition.rs +++ b/src/func/classes/composition.rs @@ -99,27 +99,34 @@ impl Monad for CompositionClass { U::bind(fa, |ua| U::fmap(V::join, V::stuff::<_, U>(V::fmap(f, ua)))) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> where Self: 'a, { - U::ibind(a, move |a| { + U::iterate_mut(a, move |a| { let fstate = f(a); U::fmap(|ustate| V::unstuff(ustate), fstate) }) } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( a: A, f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> where Self: 'a, { - U::iibind(a, ComposedBindable(f)) + U::iterate_argument(a, AComposedIterative(f)) + } + + fn iterate<'a, B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + U::iterate(ComposedIterative(f)) } fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> @@ -131,25 +138,25 @@ impl Monad for CompositionClass { } } -struct ComposedBindable(F); +struct AComposedIterative(F); impl< 'a, U: 'a + Monad, V: 'a + Monad + LocalFunctor, F: AIterative<'a, T = CompositionClass>, - > AIterative<'a> for ComposedBindable + > AIterative<'a> for AComposedIterative { type A = F::A; type B = ::F<'a, F::B>; type T = U; - fn iterate(self, a: Self::A) -> AIterativeWrapped<'a, Self> { - let fstate = self.0.iterate(a); + fn next(self, a: Self::A) -> AIterativeWrapped<'a, Self> { + let fstate = self.0.next(a); U::fmap( |ustate| match V::unstuff(ustate) { ControlFlow::Continue((next_a, next_f)) => { - ControlFlow::Continue((next_a, ComposedBindable(next_f))) + ControlFlow::Continue((next_a, Self(next_f))) } ControlFlow::Break(b) => ControlFlow::Break(b), }, @@ -158,6 +165,30 @@ impl< } } +struct ComposedIterative(F); + +impl< + 'a, + U: 'a + Monad, + V: 'a + Monad + LocalFunctor, + F: Iterative<'a, T = CompositionClass>, + > Iterative<'a> for ComposedIterative +{ + type B = ::F<'a, F::B>; + type T = U; + + fn next(self) -> IterativeWrapped<'a, Self> { + let fstate = self.0.next(); + U::fmap( + |ustate| match V::unstuff(ustate) { + ControlFlow::Continue(next_f) => ControlFlow::Continue(Self(next_f)), + ControlFlow::Break(b) => ControlFlow::Break(b), + }, + fstate, + ) + } +} + impl + LocalFunctor> MonadFail for CompositionClass { fn fail<'a, A: 'a>(e: E) -> Self::F<'a, A> where diff --git a/src/func/classes/future.rs b/src/func/classes/future.rs index e3d94b6..c545e3b 100644 --- a/src/func/classes/future.rs +++ b/src/func/classes/future.rs @@ -87,7 +87,7 @@ impl Monad for FutureClass { Box::pin(async { f(fa.await).await }) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -104,7 +104,7 @@ impl Monad for FutureClass { }) } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -113,7 +113,7 @@ impl Monad for FutureClass { { Box::pin(async move { loop { - match f.iterate(a).await { + match f.next(a).await { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), ControlFlow::Break(b) => return b, } @@ -121,6 +121,20 @@ impl Monad for FutureClass { }) } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + Box::pin(async move { + loop { + match f.next().await { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return b, + } + } + }) + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { Box::pin(async { ffa.await.await }) } diff --git a/src/func/classes/lazy.rs b/src/func/classes/lazy.rs index 3ea1f27..94d9f06 100644 --- a/src/func/classes/lazy.rs +++ b/src/func/classes/lazy.rs @@ -88,7 +88,7 @@ impl Monad for LazyClass { Box::new(|| f(fa())()) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -103,7 +103,7 @@ impl Monad for LazyClass { }) } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -111,13 +111,25 @@ impl Monad for LazyClass { Self: 'a, { loop { - match f.iterate(a)() { + match f.next(a)() { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), ControlFlow::Break(b) => return Self::pure(b), } } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + loop { + match f.next()() { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return Self::pure(b), + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { Box::new(|| ffa()()) } diff --git a/src/func/classes/option.rs b/src/func/classes/option.rs index 005dc69..d598d33 100644 --- a/src/func/classes/option.rs +++ b/src/func/classes/option.rs @@ -92,7 +92,7 @@ impl Monad for OptionClass { f(fa?) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -107,7 +107,7 @@ impl Monad for OptionClass { } } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -115,13 +115,25 @@ impl Monad for OptionClass { Self: 'a, { loop { - match f.iterate(a)? { + match f.next(a)? { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), ControlFlow::Break(b) => return Self::pure(b), } } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + loop { + match f.next()? { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return Self::pure(b), + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { ffa? } diff --git a/src/func/classes/result.rs b/src/func/classes/result.rs index 0ec3aa5..d778bcb 100644 --- a/src/func/classes/result.rs +++ b/src/func/classes/result.rs @@ -113,7 +113,7 @@ impl Monad for ResultClass { f(fa?) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -128,7 +128,7 @@ impl Monad for ResultClass { } } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -136,13 +136,25 @@ impl Monad for ResultClass { Self: 'a, { loop { - match f.iterate(a)? { + match f.next(a)? { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), ControlFlow::Break(b) => return Self::pure(b), } } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + loop { + match f.next()? { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return Self::pure(b), + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> where Self: 'a, diff --git a/src/func/classes/solo.rs b/src/func/classes/solo.rs index 0269846..4fb78fa 100644 --- a/src/func/classes/solo.rs +++ b/src/func/classes/solo.rs @@ -80,7 +80,7 @@ impl Monad for SoloClass { f(fa) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -95,7 +95,7 @@ impl Monad for SoloClass { } } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -103,13 +103,25 @@ impl Monad for SoloClass { Self: 'a, { loop { - match f.iterate(a) { + match f.next(a) { ControlFlow::Continue((new_a, new_f)) => (a, f) = (new_a, new_f), ControlFlow::Break(b) => return b, } } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + loop { + match f.next() { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return b, + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { ffa } diff --git a/src/func/classes/stackless.rs b/src/func/classes/stackless.rs index 5ec498c..a0e45c5 100644 --- a/src/func/classes/stackless.rs +++ b/src/func/classes/stackless.rs @@ -224,7 +224,7 @@ impl Monad for StacklessClass { fa.bind(f) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -233,13 +233,13 @@ impl Monad for StacklessClass { { Self::pure(a).bind(move |a| { f(a).bind(|state| match state { - ControlFlow::Continue(next_a) => Self::ibind(next_a, f), + ControlFlow::Continue(next_a) => Self::iterate_mut(next_a, f), ControlFlow::Break(b) => Self::pure(b), }) }) } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( a: A, f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -247,8 +247,20 @@ impl Monad for StacklessClass { Self: 'a, { Self::pure(a).bind(move |a| { - f.iterate(a).bind(|state| match state { - ControlFlow::Continue((next_a, next_f)) => Self::iibind(next_a, next_f), + f.next(a).bind(|state| match state { + ControlFlow::Continue((next_a, next_f)) => Self::iterate_argument(next_a, next_f), + ControlFlow::Break(b) => Self::pure(b), + }) + }) + } + + fn iterate<'a, B: 'a>(f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + Self::pure(()).bind(move |_| { + f.next().bind(|state| match state { + ControlFlow::Continue(next_f) => Self::iterate(next_f), ControlFlow::Break(b) => Self::pure(b), }) }) diff --git a/src/func/controlflow.rs b/src/func/controlflow.rs index 5df063a..cf407cc 100644 --- a/src/func/controlflow.rs +++ b/src/func/controlflow.rs @@ -32,12 +32,12 @@ impl Pure for ControlFlowClass { } /// Next [AIterative] state, wrapped. -pub type AIterativeWrapped<'a, G> = <>::T as WeakFunctor>::F< +pub type AIterativeWrapped<'a, I> = <>::T as WeakFunctor>::F< 'a, - ControlFlow<>::B, (>::A, G)>, + ControlFlow<>::B, (>::A, I)>, >; -/// Value passed to [`Monad::iibind`]. +/// Value passed to [`Monad::iterate_argument`]. /// `A` prefix meaning "with an **a**rgument" given current implementation /// relying on the argument getting passed around. pub trait AIterative<'a>: 'a + Sized { @@ -48,7 +48,7 @@ pub trait AIterative<'a>: 'a + Sized { /// Corresponding [`WeakFunctor`]. type T: 'a + ?Sized + WeakFunctor; /// Get next state. - fn iterate(self, a: Self::A) -> AIterativeWrapped<'a, Self>; + fn next(self, a: Self::A) -> AIterativeWrapped<'a, Self>; } pub struct BindableMut(F, PhantomData, PhantomData, PhantomData); @@ -78,7 +78,7 @@ impl< type B = B; type T = T; - fn iterate(mut self, a: Self::A) -> AIterativeWrapped<'a, Self> { + fn next(mut self, a: Self::A) -> AIterativeWrapped<'a, Self> { let fa = self.0(a); T::fmap( move |state| match state { @@ -89,3 +89,40 @@ impl< ) } } + +/// Next [Iterative] state, wrapped. +pub type IterativeWrapped<'a, I> = + <>::T as WeakFunctor>::F<'a, ControlFlow<>::B, I>>; + +/// Value passed to [`Monad::iterate`]. +pub trait Iterative<'a>: 'a + Sized { + /// [`ControlFlow::Break`]. + type B: 'a; + /// Corresponding [`WeakFunctor`]. + type T: 'a + ?Sized + WeakFunctor; + /// Get next state. + fn next(self) -> IterativeWrapped<'a, Self>; +} + +pub struct ArgumentedIterative(pub A, pub F); + +impl<'a, A: 'a, F: AIterative<'a, A = A>> Iterative<'a> for ArgumentedIterative +where + F::T: Functor, +{ + type B = F::B; + + type T = F::T; + + fn next(self) -> IterativeWrapped<'a, Self> { + Self::T::fmap( + |state| match state { + ControlFlow::Continue((next_a, next_f)) => { + ControlFlow::Continue(ArgumentedIterative(next_a, next_f)) + } + ControlFlow::Break(b) => ControlFlow::Break(b), + }, + self.1.next(self.0), + ) + } +} diff --git a/src/std/collections/stack.rs b/src/std/collections/stack.rs index 7062074..72c673e 100644 --- a/src/std/collections/stack.rs +++ b/src/std/collections/stack.rs @@ -157,7 +157,7 @@ impl<'a, Ctx: 'a + Context, A: Mentionable<'a, Ctx>> ExtStack<'a, Ctx, A> for St ) } fn vec(self) -> StackVecWrapped<'a, Ctx, A> { - Ctx::T::ibind((vec![], self), |(mut vec, stack)| match stack { + Ctx::T::iterate_mut((vec![], self), |(mut vec, stack)| match stack { Nullable::Null(_) => Ctx::T::pure(ControlFlow::Break(Ok(vec))), Nullable::NotNull(point) => Ctx::T::fmap( |resolved| { diff --git a/src/std/tracing.rs b/src/std/tracing.rs index d3912ea..9d5f4a8 100644 --- a/src/std/tracing.rs +++ b/src/std/tracing.rs @@ -164,7 +164,7 @@ impl Monad for TracedClass { f(fa.a).after(fa.t) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -182,7 +182,7 @@ impl Monad for TracedClass { } } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -191,7 +191,7 @@ impl Monad for TracedClass { { let mut t = TraceBox::pure(); loop { - let fa = f.iterate(a); + let fa = f.next(a); t = fa.t.after(t); match fa.a { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), @@ -200,6 +200,21 @@ impl Monad for TracedClass { } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + let mut t = TraceBox::pure(); + loop { + let fa = f.next(); + t = fa.t.after(t); + match fa.a { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return b.with_trace(t), + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> where Self::F<'a, A>: 'a, diff --git a/src/testing/counted.rs b/src/testing/counted.rs index 1ccd60f..c0bf40e 100644 --- a/src/testing/counted.rs +++ b/src/testing/counted.rs @@ -146,7 +146,7 @@ impl Monad for CountedClass { f(fa.a).add(fa.n) } - fn ibind<'a, A: 'a, B: 'a>( + fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> @@ -164,7 +164,7 @@ impl Monad for CountedClass { } } - fn iibind<'a, A: 'a, B: 'a>( + fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> @@ -173,7 +173,7 @@ impl Monad for CountedClass { { let mut n = 0; loop { - let fa = f.iterate(a); + let fa = f.next(a); n += fa.n; match fa.a { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), @@ -182,6 +182,21 @@ impl Monad for CountedClass { } } + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + let mut n = 0; + loop { + let fa = f.next(); + n += fa.n; + match fa.a { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return b.with_count(n), + } + } + } + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> where Self::F<'a, A>: 'a,