higher/
bind.rs

1use crate::Pure;
2
3/// `Bind` lets you chain computations together.
4///
5/// It takes a function `Fn(A) -> M<B>` and applies it to the `A` inside `M<A>`.
6/// You can think of this as a callback function for when the value of `A` is
7/// ready to be processed, returning the next computation in the sequence.
8///
9/// This is the primary component of the dreaded [`Monad`](crate::Monad) trait,
10/// but to be a [`Monad`](crate::Monad) a type must also implement
11/// [`Applicative`](crate::Applicative), which in turn requires implementations
12/// for [`Functor`](crate::Functor), [`Pure`](crate::Pure) and
13/// [`Apply`](crate::Apply).
14pub trait Bind<'a, A> {
15    type Target<T>;
16    fn bind<B, F>(self, f: F) -> Self::Target<B>
17    where
18        F: Fn(A) -> Self::Target<B> + 'a;
19}
20
21/// `lift_m1` provides a default implementation for
22/// [`Functor::fmap`](crate::Functor::fmap) using only [`Bind`](Bind) and
23/// [`Pure`](Pure).
24pub fn lift_m1<MA, MB, A, B, F>(f: F, a: MA) -> MB
25where
26    F: Fn(A) -> B,
27    MA: for<'a> Bind<'a, A, Target<B> = MB>,
28    MB: Pure<B>,
29{
30    a.bind::<B, _>(|x| MB::pure(f(x)))
31}
32
33impl<A> Bind<'_, A> for Option<A> {
34    type Target<T> = Option<T>;
35
36    fn bind<B, F>(self, f: F) -> Self::Target<B>
37    where
38        F: Fn(A) -> Self::Target<B>,
39    {
40        self.and_then(f)
41    }
42}
43
44impl<A, E> Bind<'_, A> for Result<A, E> {
45    type Target<T> = Result<T, E>;
46
47    fn bind<B, F>(self, f: F) -> Self::Target<B>
48    where
49        F: Fn(A) -> Self::Target<B>,
50    {
51        self.and_then(f)
52    }
53}
54
55#[cfg(feature = "std")]
56impl<A> Bind<'_, A> for Vec<A> {
57    type Target<T> = Vec<T>;
58
59    fn bind<B, F>(self, f: F) -> Self::Target<B>
60    where
61        F: Fn(A) -> Self::Target<B>,
62    {
63        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
64    }
65}
66
67#[cfg(test)]
68mod test {
69    use crate::Bind;
70
71    #[test]
72    fn bind_vec() {
73        let v = vec![1, 2, 3];
74        let o = v.bind(|i| vec![i, i + 1]);
75        assert_eq!(vec![1, 2, 2, 3, 3, 4], o);
76    }
77}