diff --git a/src/func/instances/effect.rs b/src/func/instances/effect.rs index 9610f90..0fec3ca 100644 --- a/src/func/instances/effect.rs +++ b/src/func/instances/effect.rs @@ -159,3 +159,89 @@ impl<'a, E: 'a + Send> LocalFunctor<'a> for EffectInstance { }) } } + +#[cfg(test)] +mod effect_tests { + use super::{test_suite, tests, Effect, EffectInstance, WithEffect}; + + #[derive(Debug, PartialEq)] + enum TestEffect { + Pure, + Sample, + Parallel(Box, Box), + Sequential(Box, Box), + } + + impl TestEffect { + fn is_pure(&self) -> bool { + matches!(self, Self::Pure) + } + + fn simplify(self) -> Self { + match self { + Self::Pure => Self::Pure, + Self::Sample => Self::Sample, + Self::Parallel(a, b) if a.is_pure() => *b, + Self::Parallel(a, b) if b.is_pure() => *a, + Self::Sequential(a, b) if a.is_pure() => *b, + Self::Sequential(a, b) if b.is_pure() => *a, + Self::Parallel(a, b) => match *a { + Self::Parallel(aa, ab) => { + Self::Parallel(aa, Self::Parallel(ab, b).into()).simplify() + } + a => Self::Parallel(a.simplify().into(), b.simplify().into()), + }, + Self::Sequential(a, b) => match *a { + TestEffect::Sequential(aa, ab) => { + Self::Sequential(aa, Self::Sequential(ab, b).into()).simplify() + } + a => Self::Sequential(a.simplify().into(), b.simplify().into()), + }, + } + } + } + + impl Effect for TestEffect { + fn e_pure() -> Self { + Self::Pure + } + + fn e_parallel(el: Self, er: Self) -> Self { + Self::Parallel(el.into(), er.into()) + } + + fn e_after(self, effect: Self) -> Self { + Self::Sequential(effect.into(), self.into()) + } + } + + type T = EffectInstance; + + impl<'a> tests::Eqr<'a> for T { + fn eqr( + name: &'a str, + left: Self::F, + right: Self::F, + ) -> tests::R { + tests::eqr( + name, + (left.value, left.effect.simplify()), + (right.value, right.effect.simplify()), + ) + } + } + + impl<'a> test_suite::FunctorTestSuite<'a> for T { + fn sample Self::F))>(mut f: F) { + f(&|a| WithEffect { + value: a, + effect: TestEffect::Sample, + }); + } + } + + #[test] + fn monad_follows_laws() { + test_suite::monad_follows_laws::().unwrap(); + } +}