//! [Monad] for passing and combining metadata related to the evaluation of values. //! //! For "either"/"sum" wrapping, see [`result`]. //! //! For no extra data, see [`solo`]. //! //! [`result`]: super::result //! [`solo`]: super::solo use crate::func::class_prelude::*; /// Metadata type. pub trait Effect { /// Used in [`Pure::pure`]. fn e_pure() -> Self; /// Used in [`ApplicativeLA2::la2`] and other [`Applicative`] methods. fn e_seq(el: Self, er: Self) -> Self; /// Used in [`Monad::bind`] and other [`Monad`] methods. fn e_after(self, effect: Self) -> Self; } /// Value and related metadata. #[derive(Clone)] pub struct WithEffect { pub value: A, pub effect: E, } impl WithEffect { fn e_after(self, effect: E) -> Self { WithEffect { value: self.value, effect: self.effect.e_after(effect), } } } #[derive(SharedFunctorAny)] pub struct EffectInstance(E); impl WeakFunctorAny for EffectInstance { type FAny<'a, A: 'a> = WithEffect where Self: 'a; } impl<'a, E: 'a> Functor<'a> for EffectInstance { fn fmap(fa: Self::F, f: impl 'a + FnOnce(A) -> B) -> Self::F { WithEffect { value: f(fa.value), effect: fa.effect, } } fn replace(fa: Self::F, b: B) -> Self::F { drop(fa.value); WithEffect { value: b, effect: fa.effect, } } } impl<'a, E: 'a + Effect> Pure<'a> for EffectInstance { fn pure(a: A) -> Self::F { WithEffect { value: a, effect: E::e_pure(), } } } impl<'a, E: 'a + Effect> ApplicativeSeq<'a> for EffectInstance { fn seq(ff: Self::F B>, fa: Self::F) -> Self::F { WithEffect { value: (ff.value)(fa.value), effect: E::e_seq(ff.effect, fa.effect), } } } impl<'a, E: 'a + Effect> ApplicativeLA2<'a> for EffectInstance { fn la2( fa: Self::F, fb: Self::F, f: impl 'a + FnOnce(A, B) -> C, ) -> Self::F { WithEffect { value: f(fa.value, fb.value), effect: E::e_seq(fa.effect, fb.effect), } } } impl<'a, E: 'a + Effect> ApplicativeTuple<'a> for EffectInstance { fn tuple((fa, fb): (Self::F, Self::F)) -> Self::F<(A, B)> { WithEffect { value: (fa.value, fb.value), effect: E::e_seq(fa.effect, fb.effect), } } } impl<'a, E: 'a + Effect> ApplicativeSelect<'a> for EffectInstance {} impl<'a, E: 'a + Effect> Applicative<'a> for EffectInstance { fn discard_first(fa: Self::F, fb: Self::F) -> Self::F { drop(fa.value); WithEffect { value: fb.value, effect: E::e_seq(fa.effect, fb.effect), } } fn discard_second(fa: Self::F, fb: Self::F) -> Self::F { drop(fb.value); WithEffect { value: fa.value, effect: E::e_seq(fa.effect, fb.effect), } } } impl<'a, E: 'a + Effect> Monad<'a> for EffectInstance { fn bind(fa: Self::F, f: impl 'a + FnOnce(A) -> Self::F) -> Self::F { f(fa.value).e_after(fa.effect) } fn iterate(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F { let mut effect = E::e_pure(); loop { let fa = f.next(); effect = fa.effect.e_after(effect); match fa.value { ControlFlow::Continue(next_f) => f = next_f, ControlFlow::Break(b) => return WithEffect { value: b, effect }, } } } fn join(ffa: Self::F>) -> Self::F { ffa.value.e_after(ffa.effect) } } impl<'a, E: 'a> LocalFunctor<'a> for EffectInstance { fn stuff>(fa: Self::F>) -> T::F> { T::fmap(fa.value, |a| WithEffect { value: a, effect: fa.effect, }) } }