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