diff --git a/src/func/instances/composition.rs b/src/func/instances/composition.rs index b7e9155..356fcb5 100644 --- a/src/func/instances/composition.rs +++ b/src/func/instances/composition.rs @@ -176,3 +176,41 @@ impl<'a, U: SharedFunctor<'a> + Functor<'a>, V: SharedFunctor<'a>> SharedFunctor U::fmap(U::unshare(sa), V::unshare) } } + +#[cfg(test)] +mod composition_tests { + use crate::func::instances::{option::OptionInstance, result::ResultInstance}; + + use super::{test_suite, tests, CompositionInstance}; + + type T = CompositionInstance>; + + impl<'a> tests::Eqr<'a> for T { + fn eqr( + name: &'a str, + left: Self::F, + right: Self::F, + ) -> tests::R { + tests::eqr(name, left, right) + } + } + + impl<'a> test_suite::FunctorTestSuite<'a> for T { + fn sample>>)>( + mut f: F, + ) { + OptionInstance::sample(|ua0| { + ResultInstance::sample(|a0| { + let ua0 = std::sync::Arc::new(ua0.clone_boxed()); + let a0 = std::sync::Arc::new(a0.clone_boxed()); + f(Box::new(move |a| ua0(a0(a)))) + }) + }); + } + } + + #[test] + fn monad_follows_laws() { + test_suite::monad_follows_laws::().unwrap(); + } +} diff --git a/src/func/instances/effect.rs b/src/func/instances/effect.rs index 0fec3ca..d696efb 100644 --- a/src/func/instances/effect.rs +++ b/src/func/instances/effect.rs @@ -232,11 +232,13 @@ mod effect_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|a| WithEffect { + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|a| WithEffect { value: a, effect: TestEffect::Sample, - }); + })); } } diff --git a/src/func/instances/future.rs b/src/func/instances/future.rs index 5761f68..7de9116 100644 --- a/src/func/instances/future.rs +++ b/src/func/instances/future.rs @@ -160,8 +160,10 @@ mod future_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|a| Box::pin(futures::future::ready(a))); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|a| Box::pin(futures::future::ready(a)))); } } diff --git a/src/func/instances/lazy.rs b/src/func/instances/lazy.rs index ec8adae..2f2c732 100644 --- a/src/func/instances/lazy.rs +++ b/src/func/instances/lazy.rs @@ -120,8 +120,10 @@ mod lazy_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|a| Box::new(|| a)); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|a| Box::new(|| a))); } } diff --git a/src/func/instances/option.rs b/src/func/instances/option.rs index df44f84..613c13c 100644 --- a/src/func/instances/option.rs +++ b/src/func/instances/option.rs @@ -149,9 +149,11 @@ mod option_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|_| None); - f(&|a| Some(a)); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|_| None)); + f(Box::new(|a| Some(a))); } } diff --git a/src/func/instances/result.rs b/src/func/instances/result.rs index 6ba98a7..d7cb140 100644 --- a/src/func/instances/result.rs +++ b/src/func/instances/result.rs @@ -263,12 +263,14 @@ mod result_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|_| Err(0)); - f(&|_| Err(1)); - f(&|_| Err(2)); - f(&|_| Err(3)); - f(&|a| Ok(a)); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|_| Err(0))); + f(Box::new(|_| Err(1))); + f(Box::new(|_| Err(2))); + f(Box::new(|_| Err(3))); + f(Box::new(|a| Ok(a))); } } diff --git a/src/func/instances/solo.rs b/src/func/instances/solo.rs index a06b7e9..5e94996 100644 --- a/src/func/instances/solo.rs +++ b/src/func/instances/solo.rs @@ -134,8 +134,10 @@ mod solo_tests { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|a| a); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|a| a)); } } diff --git a/src/func/instances/stackless.rs b/src/func/instances/stackless.rs index 9b6f3a5..fc47b2f 100644 --- a/src/func/instances/stackless.rs +++ b/src/func/instances/stackless.rs @@ -279,8 +279,10 @@ mod stackless_test { } impl<'a> test_suite::FunctorTestSuite<'a> for T { - fn sample Self::F))>(mut f: F) { - f(&|a| a.into()); + fn sample>>)>( + mut f: F, + ) { + f(Box::new(|a| a.into())); } } diff --git a/src/func/test_suite.rs b/src/func/test_suite.rs index b5357b0..24efcf1 100644 --- a/src/func/test_suite.rs +++ b/src/func/test_suite.rs @@ -1,8 +1,20 @@ +use std::sync::Arc; + use super::tests::*; use super::*; +pub trait WrapFunction<'a, A, B>: 'a + Send + Sync + Fn(A) -> B { + fn clone_boxed(&self) -> Box>; +} + +impl<'a, A, B, F: 'a + Send + Sync + Clone + Fn(A) -> B> WrapFunction<'a, A, B> for F { + fn clone_boxed(&self) -> Box> { + Box::new(self.clone()) + } +} + pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> { - fn sample Self::F))>(f: F); + fn sample>>)>(f: F); } pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R { @@ -49,7 +61,8 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() }); T::sample(|pa| { T::sample(|pb| { - res += discard_can_be_expressed_via_seq_or_la2::(|| pa(2), || pb(2)); + let pa = pa.clone_boxed(); + res += discard_can_be_expressed_via_seq_or_la2::(move || pa(2), move || pb(2)); }) }); T::sample(|pa| { @@ -58,7 +71,7 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() }) }); T::sample(|pa| { - res += select_of_equal_is_same::(|| pa(2)); + res += select_of_equal_is_same::(move || pa(2)); }); res } @@ -66,21 +79,29 @@ pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R { let mut res = applicative_follows_laws::(); T::sample(|pa| { - res += bind_respects_left_identity::(|x| pa(x + 3), || 2); + res += bind_respects_left_identity::(move |x| pa(x + 3), || 2); }); T::sample(|pa| { res += bind_respects_right_identity::(|| pa(2)); }); T::sample(|pa| { T::sample(|pg| { + let pa = pa.clone_boxed(); T::sample(|pf| { - res += bind_is_associative::(|x| pf(x + 5), |x| pg(x + 3), || pa(2)); + let pg = Arc::new(pg.clone_boxed()); + let pf = Arc::new(pf); + res += bind_is_associative::( + move |x| pf(x + 5), + move |x| pg(x + 3), + || pa(2), + ); }) }) }); T::sample(|pa| { T::sample(|pf| { - seq_can_be_expressed_via_bind::(|| pf(|x| x + 3), || pa(2)); + let pa = pa.clone_boxed(); + seq_can_be_expressed_via_bind::(|| pf(|x| x + 3), move || pa(2)); }) }); T::sample(|pa| { @@ -93,7 +114,14 @@ pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R { }); T::sample(|pa| { T::sample(|pb| { - res += iterate_can_be_expressed_via_bind::(|| pa(2), || |x| pb(x + 3)); + let pa = pa.clone_boxed(); + res += iterate_can_be_expressed_via_bind::( + move || pa(2), + move || { + let pb = pb.clone_boxed(); + move |x| pb(x + 3) + }, + ); }) }); res