Skip to main content

karpal_core/
plus.rs

1use crate::alt::Alt;
2use crate::hkt::OptionF;
3#[cfg(any(feature = "std", feature = "alloc"))]
4use crate::hkt::VecF;
5
6/// Plus: an Alt with a zero/empty element.
7///
8/// Laws:
9/// - Left identity: `alt(zero(), a) == a`
10/// - Right identity: `alt(a, zero()) == a`
11/// - Annihilation: `fmap(f, zero()) == zero()`
12pub trait Plus: Alt {
13    fn zero<A>() -> Self::Of<A>;
14}
15
16impl Plus for OptionF {
17    fn zero<A>() -> Option<A> {
18        None
19    }
20}
21
22// No Plus for ResultF — can't produce a Result<A, E> without an E value.
23
24#[cfg(any(feature = "std", feature = "alloc"))]
25impl Plus for VecF {
26    fn zero<A>() -> Vec<A> {
27        Vec::new()
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn option_zero() {
37        assert_eq!(OptionF::zero::<i32>(), None);
38    }
39
40    #[test]
41    fn vec_zero() {
42        assert_eq!(VecF::zero::<i32>(), Vec::<i32>::new());
43    }
44}
45
46#[cfg(test)]
47mod law_tests {
48    use super::*;
49    use crate::alt::Alt;
50    use crate::functor::Functor;
51    use proptest::prelude::*;
52
53    proptest! {
54        // Left identity: alt(zero(), a) == a
55        #[test]
56        fn option_left_identity(a in any::<Option<i32>>()) {
57            let left = OptionF::alt(OptionF::zero(), a);
58            prop_assert_eq!(left, a);
59        }
60
61        // Right identity: alt(a, zero()) == a
62        #[test]
63        fn option_right_identity(a in any::<Option<i32>>()) {
64            let left = OptionF::alt(a, OptionF::zero());
65            prop_assert_eq!(left, a);
66        }
67
68        // Annihilation: fmap(f, zero()) == zero()
69        #[test]
70        fn option_annihilation(_x in any::<i32>()) {
71            let f = |a: i32| a.wrapping_add(1);
72            let left = OptionF::fmap(OptionF::zero::<i32>(), f);
73            let right = OptionF::zero::<i32>();
74            prop_assert_eq!(left, right);
75        }
76
77        #[test]
78        fn vec_left_identity(a in prop::collection::vec(any::<i32>(), 0..10)) {
79            let left = VecF::alt(VecF::zero(), a.clone());
80            prop_assert_eq!(left, a);
81        }
82
83        #[test]
84        fn vec_right_identity(a in prop::collection::vec(any::<i32>(), 0..10)) {
85            let left = VecF::alt(a.clone(), VecF::zero());
86            prop_assert_eq!(left, a);
87        }
88    }
89}