147 lines
4.3 KiB
Rust
147 lines
4.3 KiB
Rust
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<A: 'a + Send, F: FnMut(Arc<dyn WrapFunction<'a, A, Self::F<A>>>)>(f: F);
|
|
}
|
|
|
|
pub trait FailTestSuite<'a, E: 'a + Send>: FunctorTestSuite<'a> + Fail<'a, E> {
|
|
fn sample_fail<F: FnMut(Arc<dyn 'a + Send + Sync + Fn() -> 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::<T, _>(|| pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
res += fmap_respects_composition::<T, _, _, _>(|x| x + 5, |x| x + 3, || pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
res += void_can_be_exressed_via_replace::<T, _>(|| pa(2));
|
|
});
|
|
res
|
|
}
|
|
|
|
pub fn applicative_follows_laws<'a, T: Applicative<'a> + FunctorTestSuite<'a>>() -> R {
|
|
let mut res = functor_follows_laws::<T>();
|
|
T::sample(|pa| {
|
|
res += seq_respects_identity::<T, _>(|| pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pg| {
|
|
T::sample(|pf| {
|
|
res += seq_respects_composition::<T, _, _, _, _, _>(
|
|
|| pf(|x| x + 5),
|
|
|| pg(|x| x + 3),
|
|
|| pa(2),
|
|
);
|
|
})
|
|
})
|
|
});
|
|
res += seq_is_homomorphic::<T, _, _>(|x| x + 3, || 2);
|
|
T::sample(|pf| {
|
|
res += seq_respects_interchange::<T, _, _, _>(|| pf(|x| x + 3), || 2);
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pf| {
|
|
res += seq_can_be_expressed_via_la2::<T, _, _, _>(|| pf(|x| x + 3), || pa(2));
|
|
})
|
|
});
|
|
T::sample(|pa| {
|
|
res += fmap_can_be_expressed_via_seq::<T, _, _>(|x| x + 3, || pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pb| {
|
|
let pa = pa.clone();
|
|
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _>(move || pa(2), move || pb(2));
|
|
})
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pb| {
|
|
res += tuple_can_be_expressed_via_la2::<T, _, _>(|| pa(2), || pb(2));
|
|
})
|
|
});
|
|
T::sample(|pa| {
|
|
res += select_of_equal_is_same::<T, _>(move || pa(2));
|
|
});
|
|
res
|
|
}
|
|
|
|
pub fn monad_follows_laws<'a, T: Monad<'a> + FunctorTestSuite<'a>>() -> R {
|
|
let mut res = applicative_follows_laws::<T>();
|
|
T::sample(|pa| {
|
|
res += bind_respects_left_identity::<T, _, _>(move |x| pa(x + 3), || 2);
|
|
});
|
|
T::sample(|pa| {
|
|
res += bind_respects_right_identity::<T, _>(|| pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pg| {
|
|
let pa = pa.clone();
|
|
T::sample(|pf| {
|
|
let pg = pg.clone();
|
|
res += bind_is_associative::<T, _, _, _>(
|
|
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::<T, _, _, _>(|| pf(|x| x + 3), move || pa(2));
|
|
})
|
|
});
|
|
T::sample(|pa| {
|
|
res += fmap_can_be_expressed_via_bind::<T, _, _>(|x| x + 3, || pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pb| {
|
|
res += join_can_be_expressed_via_bind::<T, _>(|| pa(pb(2)));
|
|
})
|
|
});
|
|
T::sample(|pa| {
|
|
T::sample(|pb| {
|
|
let pa = pa.clone();
|
|
res += iterate_can_be_expressed_via_bind::<T, _, _, _>(
|
|
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::<T, _>(move || pa(2));
|
|
});
|
|
T::sample(|pa| {
|
|
res += shared_is_same_after_clone::<T, _>(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::<T, _, _, _>(move || pe(), |x: i32| x + 2);
|
|
});
|
|
res
|
|
}
|