1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::Pure;

/// `Bind` lets you chain computations together.
///
/// It takes a function `Fn(A) -> M<B>` and applies it to the `A` inside `M<A>`.
/// You can think of this as a callback function for when the value of `A` is
/// ready to be processed, returning the next computation in the sequence.
///
/// This is the primary component of the dreaded [`Monad`](crate::Monad) trait,
/// but to be a [`Monad`](crate::Monad) a type must also implement
/// [`Applicative`](crate::Applicative), which in turn requires implementations
/// for [`Functor`](crate::Functor), [`Pure`](crate::Pure) and
/// [`Apply`](crate::Apply).
pub trait Bind<'a, A> {
    type Target<T>;
    fn bind<B, F>(self, f: F) -> Self::Target<B>
    where
        F: Fn(A) -> Self::Target<B> + 'a;
}

/// `lift_m1` provides a default implementation for
/// [`Functor::fmap`](crate::Functor::fmap) using only [`Bind`](Bind) and
/// [`Pure`](Pure).
pub fn lift_m1<MA, MB, A, B, F>(f: F, a: MA) -> MB
where
    F: Fn(A) -> B,
    MA: for<'a> Bind<'a, A, Target<B> = MB>,
    MB: Pure<B>,
{
    a.bind::<B, _>(|x| MB::pure(f(x)))
}

impl<A> Bind<'_, A> for Option<A> {
    type Target<T> = Option<T>;

    fn bind<B, F>(self, f: F) -> Self::Target<B>
    where
        F: Fn(A) -> Self::Target<B>,
    {
        self.and_then(f)
    }
}

impl<A, E> Bind<'_, A> for Result<A, E> {
    type Target<T> = Result<T, E>;

    fn bind<B, F>(self, f: F) -> Self::Target<B>
    where
        F: Fn(A) -> Self::Target<B>,
    {
        self.and_then(f)
    }
}

#[cfg(feature = "std")]
impl<A> Bind<'_, A> for Vec<A> {
    type Target<T> = Vec<T>;

    fn bind<B, F>(self, f: F) -> Self::Target<B>
    where
        F: Fn(A) -> Self::Target<B>,
    {
        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
    }
}

#[cfg(test)]
mod test {
    use crate::Bind;

    #[test]
    fn bind_vec() {
        let v = vec![1, 2, 3];
        let o = v.bind(|i| vec![i, i + 1]);
        assert_eq!(vec![1, 2, 2, 3, 3, 4], o);
    }
}