diff --git a/src/func/instances/effect.rs b/src/func/instances/effect.rs index 2b6a24d..3ae3e1d 100644 --- a/src/func/instances/effect.rs +++ b/src/func/instances/effect.rs @@ -169,7 +169,7 @@ mod effect_tests { #[derive(Clone, Debug, PartialEq)] enum TestEffect { Pure, - Sample, + Sample(i32), Parallel(Arc, Arc), Sequential(Arc, Arc), } @@ -182,7 +182,7 @@ mod effect_tests { fn simplify(&self) -> Arc { match self { Self::Pure => Self::Pure.into(), - Self::Sample => Self::Sample.into(), + Self::Sample(x) => Self::Sample(*x).into(), Self::Parallel(a, b) if a.is_pure() => b.clone(), Self::Parallel(a, b) if b.is_pure() => a.clone(), Self::Sequential(a, b) if a.is_pure() => b.clone(), @@ -241,7 +241,19 @@ mod effect_tests { ) { f(Arc::new(|a| WithEffect { value: a, - effect: TestEffect::Sample, + effect: TestEffect::Sample(0), + })); + f(Arc::new(|a| WithEffect { + value: a, + effect: TestEffect::Sample(1), + })); + f(Arc::new(|a| WithEffect { + value: a, + effect: TestEffect::Sample(2), + })); + f(Arc::new(|a| WithEffect { + value: a, + effect: TestEffect::Sample(3), })); } } @@ -255,4 +267,9 @@ mod effect_tests { fn shared_follows_laws() { test_suite::shared_follows_laws::().unwrap(); } + + #[test] + fn local_follows_laws() { + test_suite::local_follows_laws::().unwrap(); + } } diff --git a/src/func/instances/result.rs b/src/func/instances/result.rs index acb0428..bf0f6d8 100644 --- a/src/func/instances/result.rs +++ b/src/func/instances/result.rs @@ -299,4 +299,9 @@ mod result_tests { fn fail_follows_laws() { test_suite::fail_functor_follows_laws::().unwrap(); } + + #[test] + fn local_follows_laws() { + test_suite::local_follows_laws::().unwrap(); + } } diff --git a/src/func/test_suite.rs b/src/func/test_suite.rs index 6b239de..f7b0e04 100644 --- a/src/func/test_suite.rs +++ b/src/func/test_suite.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use super::fail::*; +use super::local::*; use super::shared::*; use super::tests::*; use super::*; @@ -144,3 +145,13 @@ pub fn fail_functor_follows_laws<'a, T: Functor<'a> + FailTestSuite<'a, E>, E: ' }); res } + +pub fn local_follows_laws<'a, T: LocalFunctor<'a> + Monad<'a> + FunctorTestSuite<'a>>() -> R { + let mut res = R::default(); + T::sample(|pa| { + T::sample(|pb| { + res += local_self_composes::(|| pa(pb(2))); + }) + }); + res +} diff --git a/src/func/tests.rs b/src/func/tests.rs index 11c0e1a..d936831 100644 --- a/src/func/tests.rs +++ b/src/func/tests.rs @@ -3,6 +3,8 @@ use std::{ ops::{Add, AddAssign}, }; +use local::LocalFunctor; + use super::applicative_select::*; use super::controlflow::*; use super::fail::*; @@ -491,3 +493,17 @@ pub fn fmap_keeps_fail< ) -> R { T::eqr("fmap fail", T::fmap(T::fail(e0()), f), T::fail(e0())) } + +pub fn local_self_composes< + 'a, + T: LocalFunctor<'a> + Monad<'a> + Eqr<'a>, + A: 'a + Send + Debug + PartialOrd, +>( + ffa0: impl Fn() -> T::F>, +) -> R { + T::eqr( + "local self", + T::join(T::stuff::<_, T>(T::stuff::<_, T>(ffa0()))), + T::join(ffa0()), + ) +}