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