From caca9add1b78a7643ae15905d6aa0ce9059d2740 Mon Sep 17 00:00:00 2001 From: timofey Date: Sun, 14 May 2023 05:56:58 +0000 Subject: [PATCH] `EffectClass` --- src/func/classes.rs | 1 + src/func/classes/effect.rs | 185 +++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/func/classes/effect.rs diff --git a/src/func/classes.rs b/src/func/classes.rs index c81f35b..14678ff 100644 --- a/src/func/classes.rs +++ b/src/func/classes.rs @@ -20,6 +20,7 @@ use crate::func::*; pub mod composition; +pub mod effect; pub mod future; pub mod lazy; pub mod option; diff --git a/src/func/classes/effect.rs b/src/func/classes/effect.rs new file mode 100644 index 0000000..760a431 --- /dev/null +++ b/src/func/classes/effect.rs @@ -0,0 +1,185 @@ +use crate::func::*; + +pub trait Effect { + fn pure() -> Self; + + fn seq(lhs: Self, rhs: Self) -> Self; + + fn after(self, effect: Self) -> Self; +} + +#[derive(Clone)] +pub struct WithEffect { + value: A, + effect: E, +} + +impl WithEffect { + fn after(self, effect: E) -> Self { + WithEffect { + value: self.value, + effect: self.effect.after(effect), + } + } +} + +#[derive(SharedFunctor, CovariantFunctor)] +pub struct EffectClass(E); + +impl WeakFunctor for EffectClass { + type F<'a, A: 'a> = WithEffect + where + Self: 'a; +} + +impl Functor for EffectClass { + fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> + where + Self: 'a, + { + WithEffect { + value: f(fa.value), + effect: fa.effect, + } + } + + fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> + where + Self: 'a, + { + drop(fa.value); + WithEffect { + value: b, + effect: fa.effect, + } + } +} + +impl Pure for EffectClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> + where + Self: 'a, + { + WithEffect { + value: a, + effect: E::pure(), + } + } +} + +impl ApplicativeSeq for EffectClass { + fn seq<'a, A: 'a, B: 'a>( + ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, + fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + WithEffect { + value: (ff.value)(fa.value), + effect: E::seq(ff.effect, fa.effect), + } + } +} + +impl ApplicativeLA2 for EffectClass { + fn la2<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(A, B) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + WithEffect { + value: f(fa.value, fb.value), + effect: E::seq(fa.effect, fb.effect), + } + } +} + +impl ApplicativeTuple for EffectClass { + fn tuple<'a, A: 'a, B: 'a>((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> + where + Self: 'a, + { + WithEffect { + value: (fa.value, fb.value), + effect: E::seq(fa.effect, fb.effect), + } + } +} + +impl Applicative for EffectClass { + fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> + where + Self: 'a, + { + drop(fa.value); + WithEffect { + value: fb.value, + effect: E::seq(fa.effect, fb.effect), + } + } + + fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> + where + Self: 'a, + { + drop(fb.value); + WithEffect { + value: fa.value, + effect: E::seq(fa.effect, fb.effect), + } + } +} + +impl Monad for EffectClass { + fn bind<'a, A: 'a, B: 'a>( + fa: Self::F<'a, A>, + f: impl 'a + FnOnce(A) -> Self::F<'a, B>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + f(fa.value).after(fa.effect) + } + + fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> + where + Self: 'a, + { + let mut effect = E::pure(); + loop { + let fa = f.next(); + effect = fa.effect.after(effect); + match fa.value { + ControlFlow::Continue(next_f) => f = next_f, + ControlFlow::Break(b) => return WithEffect { value: b, effect }, + } + } + } + + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> + where + Self::F<'a, A>: 'a, + Self: 'a, + { + ffa.value.after(ffa.effect) + } +} + +impl LocalFunctor for EffectClass { + fn stuff<'a, A: 'a, T: 'a + Pure>(fa: Self::F<'a, T::F<'a, A>>) -> T::F<'a, Self::F<'a, A>> + where + Self: 'a, + { + T::fmap( + |a| WithEffect { + value: a, + effect: fa.effect, + }, + fa.value, + ) + } +}