use std::sync::Arc; use super::fail::*; use super::shared::*; use super::tests::*; use super::*; pub trait WrapFunction<'a, A, B>: 'a + Send + Sync + Fn(A) -> B {} impl<'a, A, B, F: 'a + Send + Sync + Clone + Fn(A) -> B> WrapFunction<'a, A, B> for F {} pub trait FunctorTestSuite<'a>: WeakFunctor<'a> + Eqr<'a> { fn sample>>)>(f: F); } pub trait FailTestSuite<'a, E: 'a + Send>: FunctorTestSuite<'a> + Fail<'a, E> { fn sample_fail E>)>(f: F); } pub fn functor_follows_laws<'a, T: Functor<'a> + FunctorTestSuite<'a>>() -> R { let mut res = R::default(); T::sample(|pa| { res += fmap_respects_identity::(|| pa(2)); }); T::sample(|pa| { res += fmap_respects_composition::(|x| x + 5, |x| x + 3, || pa(2)); }); T::sample(|pa| { res += void_can_be_exressed_via_replace::(|| pa(2)); }); res } pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() -> R { let mut res = functor_follows_laws::(); T::sample(|pa| { res += seq_respects_identity::(|| pa(2)); }); T::sample(|pa| { T::sample(|pg| { T::sample(|pf| { res += seq_respects_composition::( || pf(|x| x + 5), || pg(|x| x + 3), || pa(2), ); }) }) }); res += seq_is_homomorphic::(|x| x + 3, || 2); T::sample(|pf| { res += seq_respects_interchange::(|| pf(|x| x + 3), || 2); }); T::sample(|pa| { T::sample(|pf| { res += seq_can_be_expressed_via_la2::(|| pf(|x| x + 3), || pa(2)); }) }); T::sample(|pa| { res += fmap_can_be_expressed_via_seq::(|x| x + 3, || pa(2)); }); T::sample(|pa| { T::sample(|pb| { let pa = pa.clone(); res += discard_can_be_expressed_via_seq_or_la2::(move || pa(2), move || pb(2)); }) }); T::sample(|pa| { T::sample(|pb| { res += tuple_can_be_expressed_via_la2::(|| pa(2), || pb(2)); }) }); T::sample(|pa| { res += select_of_equal_is_same::(move || pa(2)); }); res } 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::(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(); T::sample(|pf| { let pg = pg.clone(); res += bind_is_associative::( move |x| pf(x + 5), move |x| pg(x + 3), || pa(2), ); }) }) }); T::sample(|pa| { T::sample(|pf| { let pa = pa.clone(); seq_can_be_expressed_via_bind::(|| pf(|x| x + 3), move || pa(2)); }) }); T::sample(|pa| { res += fmap_can_be_expressed_via_bind::(|x| x + 3, || pa(2)); }); T::sample(|pa| { T::sample(|pb| { res += join_can_be_expressed_via_bind::(|| pa(pb(2))); }) }); T::sample(|pa| { T::sample(|pb| { let pa = pa.clone(); res += iterate_can_be_expressed_via_bind::( move || pa(2), move || { let pb = pb.clone(); move |x| pb(x + 3) }, ); }) }); res } pub fn shared_follows_laws<'a, T: SharedFunctor<'a> + FunctorTestSuite<'a>>() -> R { let mut res = R::default(); T::sample(|pa| { res += shared_is_same_as_original::(move || pa(2)); }); T::sample(|pa| { res += shared_is_same_after_clone::(move || pa(2)); }); res } pub fn fail_functor_follows_laws<'a, T: Functor<'a> + FailTestSuite<'a, E>, E: 'a + Send>() -> R { let mut res = R::default(); T::sample_fail(|pe| { res += fmap_keeps_fail::(move || pe(), |x: i32| x + 2); }); res }