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