higher_cat/
bind.rs

1use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
2use std::hash::{BuildHasher, Hash};
3
4use higher::Lift;
5
6/// `Bind` lets you chain computations together.
7///
8/// It takes a function `Fn(A) -> M<B>` and applies it to the `A` inside `M<A>`.
9/// You can think of this as a callback function for when the value of `A` is
10/// ready to be processed, returning the next computation in the sequence.
11pub trait Bind<A, B>: Lift<A, B> {
12    /// Use the value inside an `M<A>: Bind` to create an `M<B>`.
13    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
14    where
15        F: Fn(A) -> <Self as Lift<A, B>>::Target1;
16}
17
18impl<A, B> Bind<A, B> for Option<A> {
19    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
20    where
21        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
22    {
23        self.and_then(f)
24    }
25}
26
27impl<A, B, E> Bind<A, B> for Result<A, E> {
28    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
29    where
30        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
31    {
32        self.and_then(f)
33    }
34}
35
36impl<A, B> Bind<A, B> for Vec<A> {
37    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
38    where
39        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
40    {
41        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
42    }
43}
44
45impl<A, B> Bind<A, B> for VecDeque<A> {
46    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
47    where
48        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
49    {
50        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
51    }
52}
53
54impl<A, B> Bind<A, B> for LinkedList<A> {
55    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
56    where
57        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
58    {
59        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
60    }
61}
62
63impl<A, B> Bind<A, B> for BinaryHeap<A>
64where
65    A: Ord,
66    B: Ord,
67{
68    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
69    where
70        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
71    {
72        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
73    }
74}
75
76impl<A, B> Bind<A, B> for BTreeSet<A>
77where
78    A: Ord,
79    B: Ord,
80{
81    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
82    where
83        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
84    {
85        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
86    }
87}
88
89impl<A, B, S> Bind<A, B> for HashSet<A, S>
90where
91    A: Hash + Eq,
92    B: Hash + Eq,
93    S: BuildHasher + Default,
94{
95    fn bind<F>(self, f: F) -> <Self as Lift<A, B>>::Target1
96    where
97        F: Fn(A) -> <Self as Lift<A, B>>::Target1,
98    {
99        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
100    }
101}
102
103impl<A, B, C, D, S> Bind<(A, B), (C, D)> for HashMap<A, B, S>
104where
105    A: Hash + Eq,
106    B: Hash + Eq,
107    C: Hash + Eq,
108    D: Hash + Eq,
109    S: BuildHasher + Default,
110{
111    fn bind<F>(self, f: F) -> <Self as Lift<(A, B), (C, D)>>::Target1
112    where
113        F: Fn((A, B)) -> <Self as Lift<(A, B), (C, D)>>::Target1,
114    {
115        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
116    }
117}
118
119impl<A, B, C, D> Bind<(A, B), (C, D)> for BTreeMap<A, B>
120where
121    A: Ord,
122    B: Ord,
123    C: Ord,
124    D: Ord,
125{
126    fn bind<F>(self, f: F) -> <Self as Lift<(A, B), (C, D)>>::Target1
127    where
128        F: Fn((A, B)) -> <Self as Lift<(A, B), (C, D)>>::Target1,
129    {
130        self.into_iter().flat_map(|v| f(v).into_iter()).collect()
131    }
132}
133
134#[cfg(test)]
135mod test {
136    use super::*;
137    use crate::Pure;
138    use proptest::collection::vec;
139    use proptest::num::u8;
140    use proptest::proptest;
141
142    #[test]
143    fn bind_vec() {
144        let v = vec![1, 2, 3];
145        let o = v.bind(|i| vec![i, i + 1]);
146        assert_eq!(vec![1, 2, 2, 3, 3, 4], o);
147    }
148
149    proptest! {
150        #[test]
151        fn identity(v in vec(u8::ANY, 0..1000)) {
152            let orig = v.clone();
153            let result = v.bind(Pure::pure);
154            assert_eq!(orig, result);
155        }
156    }
157}