Skip to main content

karpal_core/
monad.rs

1use crate::applicative::Applicative;
2use crate::chain::Chain;
3
4/// Monad: Applicative + Chain with no extra methods (blanket impl).
5///
6/// Laws:
7/// - Left identity: `chain(pure(a), f) == f(a)`
8/// - Right identity: `chain(m, pure) == m`
9pub trait Monad: Applicative + Chain {}
10
11impl<F: Applicative + Chain> Monad for F {}
12
13#[cfg(test)]
14mod law_tests {
15    use crate::applicative::Applicative;
16    use crate::chain::Chain;
17    use crate::hkt::OptionF;
18    #[cfg(any(feature = "std", feature = "alloc"))]
19    use crate::hkt::VecF;
20    use proptest::prelude::*;
21
22    proptest! {
23        // Left identity: chain(pure(a), f) == f(a)
24        #[test]
25        fn option_left_identity(a in any::<i32>()) {
26            let f = |x: i32| Some(x.wrapping_mul(2));
27            let left = OptionF::chain(OptionF::pure(a), f);
28            let right = f(a);
29            prop_assert_eq!(left, right);
30        }
31
32        // Right identity: chain(m, pure) == m
33        #[test]
34        fn option_right_identity(m in any::<Option<i32>>()) {
35            let left = OptionF::chain(m, OptionF::pure);
36            prop_assert_eq!(left, m);
37        }
38
39        #[test]
40        fn vec_left_identity(a in any::<i32>()) {
41            let f = |x: i32| vec![x, x.wrapping_add(1)];
42            let left = VecF::chain(VecF::pure(a), f);
43            let right = f(a);
44            prop_assert_eq!(left, right);
45        }
46
47        #[test]
48        fn vec_right_identity(m in prop::collection::vec(any::<i32>(), 0..10)) {
49            let left = VecF::chain(m.clone(), VecF::pure);
50            prop_assert_eq!(left, m);
51        }
52    }
53}