Skip to main content

lifted/
monad.rs

1//! The higher-kinded trait of a `Monad`.
2
3use super::applicative::Applicative;
4use super::*;
5use super::types::*;
6
7pub trait Monad: Applicative {
8    fn bind<A, B, F: Fn(A) -> K1<Self, B>>(a: K1<Self, A>, f: F) -> K1<Self, B>;
9}
10
11impl Monad for OptionC {
12    fn bind<A, B, G: Fn(A) -> K1<Self, B>>(a: K1<Self, A>, g: G) -> K1<Self, B> {
13        match a.into_inner() {
14            Some(x) => g(x),
15            None => OptionC::new(None),
16        }
17    }
18}
19
20impl Monad for VecC {
21    fn bind<A, B, G: Fn(A) -> K1<Self, B>>(a: K1<Self, A>, g: G) -> K1<Self, B> {
22        Self::new(
23            a.into_inner()
24                .into_iter()
25                .flat_map(move |x| g(x).into_inner())
26                .collect()
27        )
28    }
29}
30
31#[cfg(test)]
32mod test {
33    use super::*;
34
35    fn check_law_left_identity<M: Monad, A, B, F>(a: A, f: F)
36    where
37        M: Kind1<B>,
38        A: Clone,
39        F: Fn(A) -> K1<M, B> + Clone,
40        K1<M, B>: PartialEq + Clone + core::fmt::Debug,
41    {
42        let return_bind = M::bind(M::pure(a.clone()), f.clone());
43        let just_call = f(a);
44        assert_eq!(return_bind, just_call);
45    }
46
47    fn check_law_right_identity<T: Clone, M: Monad>(m: K1<M, T>)
48    where
49        M: Kind1<T>,
50        K1<M, T>: PartialEq + Clone + core::fmt::Debug,
51    {
52        let m_return = M::bind(m.clone(), M::pure);
53        assert_eq!(m_return, m);
54    }
55
56    fn check_law_associativity<A, B, C, M: Monad, F, G>(m: K1<M, A>, f: F, g: G)
57    where
58        M: Kind1<A> + Kind1<C>,
59        K1<M, A>: Clone,
60        K1<M, C>: PartialEq + Clone + core::fmt::Debug,
61        F: Fn(A) -> K1<M, B> + Clone,
62        G: Fn(B) -> K1<M, C> + Clone,
63    {
64        let left_first = M::bind(M::bind(m.clone(), f.clone()), g.clone());
65        let right_first = M::bind(m, move |x| M::bind(f(x), g.clone()));
66        assert_eq!(left_first, right_first);
67    }
68
69    #[test]
70    fn option_monad_law_left_identity() {
71        check_law_left_identity(42, |x| OptionC::new(Some(x + 1)));
72    }
73
74    #[test]
75    fn option_monad_law_right_identity() {
76        check_law_right_identity::<i32, _>(OptionC::new(None));
77        check_law_right_identity(OptionC::new(Some(42)));
78    }
79
80    #[test]
81    fn option_monad_law_associativity() {
82        check_law_associativity(
83            OptionC::new(Some(42)),
84            |x| OptionC::new(Some(x + 1)),
85            |x| OptionC::new(Some(x * 2)),
86        );
87        check_law_associativity::<i32, _, _, _, _, _>(
88            OptionC::new(None),
89            |x| OptionC::new(Some(x + 1)),
90            |x| OptionC::new(Some(x * 2)),
91        );
92        check_law_associativity::<_, i32, _, _, _, _>(
93            OptionC::new(Some(42)),
94            |_| OptionC::new(None),
95            |x| OptionC::new(Some(x * 2)),
96        );
97        check_law_associativity::<_, _, i32, _, _, _>(
98            OptionC::new(Some(42)),
99            |x| OptionC::new(Some(x + 1)),
100            |_| OptionC::new(None),
101        );
102    }
103
104    #[test]
105    fn vec_monad_law_left_identity() {
106        check_law_left_identity(42, |x| VecC::new(vec![x + 1]));
107    }
108
109    #[test]
110    fn vec_monad_law_right_identity() {
111        check_law_right_identity::<i32, _>(VecC::new(vec![]));
112        check_law_right_identity(VecC::new(vec![42]));
113    }
114
115    #[test]
116    fn vec_monad_law_associativity() {
117        check_law_associativity(
118            VecC::new(vec![42, 0]),
119            |x| VecC::new(vec![x + 1, x - 1]),
120            |x| VecC::new(vec![x * 2, x]),
121        );
122        check_law_associativity::<i32, _, _, _, _, _>(
123            VecC::new(vec![]),
124            |x| VecC::new(vec![x + 1, x - 1]),
125            |x| VecC::new(vec![x * 2, x]),
126        );
127        check_law_associativity::<_, i32, _, _, _, _>(
128            VecC::new(vec![42, 0]),
129            |_| VecC::new(vec![]),
130            |x| VecC::new(vec![x * 2, x]),
131        );
132        check_law_associativity::<_, _, i32, _, _, _>(
133            VecC::new(vec![42, 0]),
134            |x| VecC::new(vec![x + 1, x - 1]),
135            |_| VecC::new(vec![]),
136        );
137    }
138}