1use core::marker::PhantomData;
5
6use karpal_core::hkt::HKT;
7
8pub trait Ran<G: HKT, H: HKT> {
35 type Input;
37
38 fn run_ran<R>(&self, k: impl Fn(Self::Input) -> G::Of<R>) -> H::Of<R>;
40}
41
42pub fn ran_fmap<G, H, A, B, T, F>(ran: T, f: F) -> RanMapped<G, H, A, B, T, F>
50where
51 G: HKT,
52 H: HKT,
53 T: Ran<G, H, Input = A>,
54 F: Fn(A) -> B,
55{
56 RanMapped {
57 ran,
58 f,
59 _marker: PhantomData,
60 }
61}
62
63pub struct RanMapped<G: HKT, H: HKT, A, B, T, F> {
65 ran: T,
66 f: F,
67 _marker: PhantomData<(G, H, A, B)>,
68}
69
70impl<G, H, A, B, T, F> Ran<G, H> for RanMapped<G, H, A, B, T, F>
71where
72 G: HKT,
73 H: HKT,
74 T: Ran<G, H, Input = A>,
75 F: Fn(A) -> B,
76{
77 type Input = B;
78
79 fn run_ran<R>(&self, k: impl Fn(B) -> G::Of<R>) -> H::Of<R> {
80 let f_ref = &self.f;
81 self.ran.run_ran(move |a| k(f_ref(a)))
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use karpal_core::hkt::OptionF;
89
90 struct SimpleRan(i32);
91
92 impl Ran<OptionF, OptionF> for SimpleRan {
93 type Input = i32;
94 fn run_ran<R>(&self, k: impl Fn(i32) -> Option<R>) -> Option<R> {
95 k(self.0)
96 }
97 }
98
99 #[test]
100 fn basic_ran() {
101 let ran = SimpleRan(42);
102 let result = ran.run_ran(|x| Some(x * 2));
103 assert_eq!(result, Some(84));
104 }
105
106 #[test]
107 fn ran_with_none() {
108 let ran = SimpleRan(0);
109 let result: Option<i32> = ran.run_ran(|_| None);
110 assert_eq!(result, None);
111 }
112
113 #[test]
114 fn ran_fmap_basic() {
115 let ran = SimpleRan(10);
116 let mapped = ran_fmap(ran, |x| x + 5);
117 let result = mapped.run_ran(|x| Some(x * 2));
118 assert_eq!(result, Some(30));
122 }
123
124 #[test]
125 fn ran_fmap_identity() {
126 let ran = SimpleRan(7);
127 let mapped = ran_fmap(ran, |x: i32| x);
128 let result = mapped.run_ran(Some);
129 assert_eq!(result, Some(7));
130 }
131
132 #[test]
133 fn ran_fmap_composition() {
134 let f = |x: i32| x + 1;
135 let g = |x: i32| x * 2;
136
137 let left = ran_fmap(SimpleRan(5), move |a| g(f(a)));
138 let right = ran_fmap(ran_fmap(SimpleRan(5), f), g);
139
140 let left_result = left.run_ran(Some);
141 let right_result = right.run_ran(Some);
142 assert_eq!(left_result, right_result);
143 }
144
145 #[test]
147 fn ran_as_codensity() {
148 let ran = SimpleRan(42);
152 let result = ran.run_ran(Some);
154 assert_eq!(result, Some(42));
155 }
156
157 struct VecToOption(Vec<i32>);
159
160 impl Ran<OptionF, OptionF> for VecToOption {
161 type Input = i32;
162 fn run_ran<R>(&self, k: impl Fn(i32) -> Option<R>) -> Option<R> {
163 self.0.first().and_then(|&x| k(x))
165 }
166 }
167
168 #[test]
169 fn ran_different_impl() {
170 let ran = VecToOption(vec![10, 20, 30]);
171 let result = ran.run_ran(|x| Some(x.to_string()));
172 assert_eq!(result, Some("10".to_string()));
173 }
174
175 #[test]
176 fn ran_different_impl_empty() {
177 let ran = VecToOption(vec![]);
178 let result: Option<String> = ran.run_ran(|x| Some(x.to_string()));
179 assert_eq!(result, None);
180 }
181}
182
183#[cfg(test)]
184mod law_tests {
185 use super::*;
186 use karpal_core::hkt::OptionF;
187 use proptest::prelude::*;
188
189 struct PureRan(i32);
190
191 impl Ran<OptionF, OptionF> for PureRan {
192 type Input = i32;
193 fn run_ran<R>(&self, k: impl Fn(i32) -> Option<R>) -> Option<R> {
194 k(self.0)
195 }
196 }
197
198 proptest! {
199 #[test]
201 fn functor_identity(x in any::<i32>()) {
202 let original = PureRan(x).run_ran(Some);
203 let mapped = ran_fmap(PureRan(x), |a: i32| a).run_ran(Some);
204 prop_assert_eq!(original, mapped);
205 }
206
207 #[test]
209 fn functor_composition(x in any::<i32>()) {
210 let f = |a: i32| a.wrapping_add(1);
211 let g = |a: i32| a.wrapping_mul(2);
212
213 let left = ran_fmap(PureRan(x), move |a| g(f(a))).run_ran(Some);
214 let right = ran_fmap(ran_fmap(PureRan(x), f), g).run_ran(Some);
215 prop_assert_eq!(left, right);
216 }
217 }
218}