1use crate::hkt::{HKT2, ResultBF, TupleF};
5
6pub trait Bifunctor: HKT2 {
12 fn bimap<A, B, C, D>(
13 fab: Self::P<A, B>,
14 f: impl Fn(A) -> C,
15 g: impl Fn(B) -> D,
16 ) -> Self::P<C, D>;
17
18 fn first<A, B, C>(fab: Self::P<A, B>, f: impl Fn(A) -> C) -> Self::P<C, B> {
19 Self::bimap(fab, f, |b| b)
20 }
21
22 fn second<A, B, D>(fab: Self::P<A, B>, g: impl Fn(B) -> D) -> Self::P<A, D> {
23 Self::bimap(fab, |a| a, g)
24 }
25}
26
27impl Bifunctor for ResultBF {
28 fn bimap<A, B, C, D>(
29 fab: Result<B, A>,
30 f: impl Fn(A) -> C,
31 g: impl Fn(B) -> D,
32 ) -> Result<D, C> {
33 match fab {
34 Ok(b) => Ok(g(b)),
35 Err(a) => Err(f(a)),
36 }
37 }
38}
39
40impl Bifunctor for TupleF {
41 fn bimap<A, B, C, D>(fab: (A, B), f: impl Fn(A) -> C, g: impl Fn(B) -> D) -> (C, D) {
42 (f(fab.0), g(fab.1))
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn result_bimap_ok() {
52 let r: Result<i32, &str> = Ok(5);
53 let result = ResultBF::bimap(r, |s| s.len(), |n| n * 2);
54 assert_eq!(result, Ok(10));
55 }
56
57 #[test]
58 fn result_bimap_err() {
59 let r: Result<i32, &str> = Err("hello");
60 let result = ResultBF::bimap(r, |s| s.len(), |n| n * 2);
61 assert_eq!(result, Err(5));
62 }
63
64 #[test]
65 fn result_first() {
66 let r: Result<i32, &str> = Err("hi");
67 let result = ResultBF::first(r, |s| s.len());
68 assert_eq!(result, Err(2));
69 }
70
71 #[test]
72 fn result_second() {
73 let r: Result<i32, &str> = Ok(5);
74 let result = ResultBF::second(r, |n| n * 3);
75 assert_eq!(result, Ok(15));
76 }
77
78 #[test]
79 fn tuple_bimap() {
80 assert_eq!(TupleF::bimap((1, "hi"), |x| x + 1, |s| s.len()), (2, 2));
81 }
82
83 #[test]
84 fn tuple_first() {
85 assert_eq!(TupleF::first((1, "hi"), |x| x * 2), (2, "hi"));
86 }
87
88 #[test]
89 fn tuple_second() {
90 assert_eq!(TupleF::second((1, "hi"), |s| s.len()), (1, 2));
91 }
92}
93
94#[cfg(test)]
95mod law_tests {
96 use super::*;
97 use proptest::prelude::*;
98
99 proptest! {
100 #[test]
102 fn tuple_identity(a in any::<i32>(), b in any::<i32>()) {
103 let fab = (a, b);
104 let result = TupleF::bimap(fab, |x| x, |y| y);
105 prop_assert_eq!(result, (a, b));
106 }
107
108 #[test]
110 fn tuple_composition(a in any::<i16>(), b in any::<i16>()) {
111 let fab = (a, b);
112 let f = |x: i16| x.wrapping_add(1);
113 let g = |x: i16| x.wrapping_mul(2);
114 let h = |x: i16| x.wrapping_add(3);
115 let i_fn = |x: i16| x.wrapping_mul(4);
116
117 let left = TupleF::bimap(fab, |x| f(g(x)), |y| h(i_fn(y)));
118 let right = TupleF::bimap(TupleF::bimap(fab, g, i_fn), f, h);
119 prop_assert_eq!(left, right);
120 }
121
122 #[test]
123 fn result_identity(x in any::<Result<i32, i32>>()) {
124 let result = ResultBF::bimap(x, |a| a, |b| b);
125 prop_assert_eq!(result, x);
126 }
127
128 #[test]
129 fn result_composition(x in any::<Result<i16, i16>>()) {
130 let f = |x: i16| x.wrapping_add(1);
131 let g = |x: i16| x.wrapping_mul(2);
132 let h = |x: i16| x.wrapping_add(3);
133 let i_fn = |x: i16| x.wrapping_mul(4);
134
135 let left = ResultBF::bimap(x, |a| f(g(a)), |b| h(i_fn(b)));
136 let right = ResultBF::bimap(ResultBF::bimap(x, g, i_fn), f, h);
137 prop_assert_eq!(left, right);
138 }
139 }
140}