Skip to main content

karpal_core/
alternative.rs

1use crate::applicative::Applicative;
2use crate::plus::Plus;
3
4/// Alternative: Applicative + Plus with no extra methods (blanket impl).
5///
6/// Laws:
7/// - Distributivity: `ap(alt(f, g), x) == alt(ap(f, x), ap(g, x))`
8/// - Annihilation: `ap(zero(), x) == zero()`
9pub trait Alternative: Applicative + Plus {}
10
11impl<F: Applicative + Plus> Alternative for F {}
12
13#[cfg(test)]
14mod law_tests {
15    use crate::alt::Alt;
16    use crate::apply::Apply;
17    use crate::hkt::OptionF;
18    use crate::plus::Plus;
19    use proptest::prelude::*;
20
21    proptest! {
22        // Distributivity: ap(alt(f, g), x) == alt(ap(f, x), ap(g, x))
23        #[test]
24        fn option_distributivity(x in any::<i16>()) {
25            let f: Option<fn(i16) -> i16> = Some(|a| a.wrapping_add(1));
26            let g: Option<fn(i16) -> i16> = Some(|a| a.wrapping_mul(2));
27
28            let left = OptionF::ap(OptionF::alt(f, g), Some(x));
29            let right = OptionF::alt(OptionF::ap(f, Some(x)), OptionF::ap(g, Some(x)));
30            prop_assert_eq!(left, right);
31        }
32
33        // Annihilation: ap(zero(), x) == zero()
34        #[test]
35        fn option_annihilation(x in any::<Option<i32>>()) {
36            let left = OptionF::ap(OptionF::zero::<fn(i32) -> i32>(), x);
37            let right: Option<i32> = OptionF::zero();
38            prop_assert_eq!(left, right);
39        }
40    }
41}