fp_library/types/optics/traversal.rs
1//! Traversal optics for operating on multiple foci.
2//!
3//! A traversal represents a way to focus on zero or more values in a structure
4//! and update them while maintaining the structure.
5
6#[fp_macros::document_module]
7mod inner {
8 use {
9 crate::{
10 Apply,
11 brands::{
12 FnBrand,
13 optics::*,
14 },
15 classes::{
16 ToDynCloneFn,
17 monoid::Monoid,
18 optics::*,
19 profunctor::Wander,
20 },
21 kinds::*,
22 },
23 fp_macros::*,
24 std::marker::PhantomData,
25 };
26
27 /// A polymorphic traversal.
28 ///
29 /// Matches PureScript's `Traversal s t a b`.
30 #[document_type_parameters(
31 "The lifetime of the values.",
32 "The reference-counted pointer type.",
33 "The source type of the structure.",
34 "The target type of the structure after an update.",
35 "The source type of the focus.",
36 "The target type of the focus after an update.",
37 "The type of the traversal function."
38 )]
39 pub struct Traversal<'a, PointerBrand, S, T, A, B, F>
40 where
41 PointerBrand: ToDynCloneFn,
42 F: TraversalFunc<'a, S, T, A, B> + 'a,
43 S: 'a,
44 T: 'a,
45 A: 'a,
46 B: 'a, {
47 /// The traversal function.
48 ///
49 /// In PureScript this is `(forall f. Applicative f => (a -> f b) -> s -> f t)`.
50 pub traversal: F,
51 pub(crate) _phantom: PhantomData<(&'a (S, T, A, B), PointerBrand)>,
52 }
53
54 #[document_type_parameters(
55 "The lifetime of the values.",
56 "The reference-counted pointer type.",
57 "The source type of the structure.",
58 "The target type of the structure after an update.",
59 "The source type of the focus.",
60 "The target type of the focus after an update.",
61 "The type of the traversal function."
62 )]
63 impl<'a, PointerBrand, S, T, A, B, F> Traversal<'a, PointerBrand, S, T, A, B, F>
64 where
65 PointerBrand: ToDynCloneFn,
66 F: TraversalFunc<'a, S, T, A, B> + 'a,
67 {
68 /// Creates a new `Traversal` instance.
69 #[document_signature]
70 ///
71 #[document_parameters("The traversal function.")]
72 ///
73 #[document_returns("A new instance of the type.")]
74 ///
75 #[document_examples]
76 ///
77 /// ```
78 /// use fp_library::{
79 /// Apply,
80 /// brands::*,
81 /// classes::{
82 /// Applicative,
83 /// lift::Lift,
84 /// optics::traversal::TraversalFunc,
85 /// pointed::Pointed,
86 /// },
87 /// kinds::*,
88 /// types::optics::Traversal,
89 /// };
90 ///
91 /// #[derive(Clone)]
92 /// struct ListTraversal;
93 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
94 /// fn apply<M: Applicative>(
95 /// &self,
96 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
97 /// s: Vec<A>,
98 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
99 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
100 /// M::lift2(
101 /// |mut v: Vec<A>, x: A| {
102 /// v.push(x);
103 /// v
104 /// },
105 /// acc,
106 /// f(a),
107 /// )
108 /// })
109 /// }
110 /// }
111 ///
112 /// let traversal = Traversal::<'_, RcBrand, Vec<i32>, Vec<i32>, i32, i32, _>::new(ListTraversal);
113 /// assert_eq!(
114 /// traversal.traversal.apply::<OptionBrand>(Box::new(|x| Some(x + 1)), vec![1, 2]),
115 /// Some(vec![2, 3])
116 /// );
117 /// ```
118 pub fn new(traversal: F) -> Self {
119 Traversal {
120 traversal,
121 _phantom: PhantomData,
122 }
123 }
124 }
125
126 /// A monomorphic traversal.
127 ///
128 /// Matches PureScript's `Traversal' s a`.
129 #[document_type_parameters(
130 "The lifetime of the values.",
131 "The reference-counted pointer type.",
132 "The type of the structure.",
133 "The type of the focus.",
134 "The type of the traversal function."
135 )]
136 pub struct TraversalPrime<'a, PointerBrand, S, A, F>
137 where
138 PointerBrand: ToDynCloneFn,
139 F: TraversalFunc<'a, S, S, A, A> + 'a,
140 S: 'a,
141 A: 'a, {
142 /// The traversal function.
143 pub traversal: F,
144 pub(crate) _phantom: PhantomData<(&'a (S, A), PointerBrand)>,
145 }
146
147 #[document_type_parameters(
148 "The lifetime of the values.",
149 "The reference-counted pointer type.",
150 "The type of the structure.",
151 "The type of the focus.",
152 "The type of the traversal function."
153 )]
154 impl<'a, PointerBrand, S, A, F> TraversalPrime<'a, PointerBrand, S, A, F>
155 where
156 PointerBrand: ToDynCloneFn,
157 F: TraversalFunc<'a, S, S, A, A> + 'a,
158 {
159 /// Creates a new `TraversalPrime` instance.
160 #[document_signature]
161 ///
162 #[document_parameters("The traversal function.")]
163 ///
164 #[document_returns("A new instance of the type.")]
165 ///
166 #[document_examples]
167 ///
168 /// ```
169 /// use fp_library::{
170 /// Apply,
171 /// brands::*,
172 /// classes::{
173 /// Applicative,
174 /// lift::Lift,
175 /// optics::traversal::TraversalFunc,
176 /// pointed::Pointed,
177 /// },
178 /// kinds::*,
179 /// types::optics::TraversalPrime,
180 /// };
181 ///
182 /// #[derive(Clone)]
183 /// struct ListTraversal;
184 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
185 /// fn apply<M: Applicative>(
186 /// &self,
187 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
188 /// s: Vec<A>,
189 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
190 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
191 /// M::lift2(
192 /// |mut v: Vec<A>, x: A| {
193 /// v.push(x);
194 /// v
195 /// },
196 /// acc,
197 /// f(a),
198 /// )
199 /// })
200 /// }
201 /// }
202 ///
203 /// let traversal = TraversalPrime::<'_, RcBrand, Vec<i32>, i32, _>::new(ListTraversal);
204 /// assert_eq!(
205 /// traversal.traversal.apply::<OptionBrand>(Box::new(|x| Some(x + 1)), vec![1, 2]),
206 /// Some(vec![2, 3])
207 /// );
208 /// ```
209 pub fn new(traversal: F) -> Self {
210 TraversalPrime {
211 traversal,
212 _phantom: PhantomData,
213 }
214 }
215 }
216
217 #[document_type_parameters(
218 "The lifetime of the values.",
219 "The profunctor type.",
220 "The reference-counted pointer type.",
221 "The source type of the structure.",
222 "The target type of the structure after an update.",
223 "The source type of the focus.",
224 "The target type of the focus after an update.",
225 "The type of the traversal function."
226 )]
227 #[document_parameters("The traversal instance.")]
228 impl<'a, Q, PointerBrand, S, T, A, B, F> Optic<'a, Q, S, T, A, B>
229 for Traversal<'a, PointerBrand, S, T, A, B, F>
230 where
231 Q: Wander,
232 PointerBrand: ToDynCloneFn,
233 F: TraversalFunc<'a, S, T, A, B> + Clone + 'a,
234 S: 'a,
235 T: 'a,
236 A: 'a,
237 B: 'a + Clone,
238 {
239 /// Evaluates the traversal with a profunctor.
240 #[document_signature]
241 ///
242 #[document_parameters("The profunctor value to transform.")]
243 ///
244 #[document_returns("The transformed profunctor value.")]
245 ///
246 #[document_examples]
247 ///
248 /// ```
249 /// use fp_library::{
250 /// Apply,
251 /// brands::*,
252 /// classes::{
253 /// Applicative,
254 /// lift::Lift,
255 /// optics::{
256 /// traversal::TraversalFunc,
257 /// *,
258 /// },
259 /// pointed::Pointed,
260 /// profunctor::*,
261 /// },
262 /// kinds::*,
263 /// types::optics::Traversal,
264 /// };
265 ///
266 /// #[derive(Clone)]
267 /// struct ListTraversal;
268 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
269 /// fn apply<M: Applicative>(
270 /// &self,
271 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
272 /// s: Vec<A>,
273 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
274 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
275 /// M::lift2(
276 /// |mut v: Vec<A>, x: A| {
277 /// v.push(x);
278 /// v
279 /// },
280 /// acc,
281 /// f(a),
282 /// )
283 /// })
284 /// }
285 /// }
286 ///
287 /// let traversal = Traversal::<'_, RcBrand, Vec<i32>, Vec<i32>, i32, i32, _>::new(ListTraversal);
288 /// let f = std::rc::Rc::new(|x: i32| x + 1) as std::rc::Rc<dyn Fn(i32) -> i32>;
289 /// let result: std::rc::Rc<dyn Fn(Vec<i32>) -> Vec<i32>> =
290 /// Optic::<'_, RcFnBrand, _, _, _, _>::evaluate(&traversal, f);
291 /// assert_eq!(result(vec![1, 2]), vec![2, 3]);
292 /// ```
293 fn evaluate(
294 &self,
295 pab: Apply!(<Q as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, A, B>),
296 ) -> Apply!(<Q as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, S, T>) {
297 Q::wander(self.traversal.clone(), pab)
298 }
299 }
300
301 #[document_type_parameters(
302 "The lifetime of the values.",
303 "The reference-counted pointer type.",
304 "The source type of the structure.",
305 "The target type of the structure after an update.",
306 "The source type of the focus.",
307 "The target type of the focus after an update.",
308 "The type of the traversal function."
309 )]
310 #[document_parameters("The traversal instance.")]
311 impl<'a, PointerBrand, S, T, A, B, F> TraversalOptic<'a, S, T, A, B>
312 for Traversal<'a, PointerBrand, S, T, A, B, F>
313 where
314 PointerBrand: ToDynCloneFn,
315 F: TraversalFunc<'a, S, T, A, B> + Clone + 'a,
316 S: 'a,
317 T: 'a,
318 A: 'a,
319 B: 'a + Clone,
320 {
321 #[document_signature]
322 #[document_type_parameters("The profunctor type.")]
323 #[document_parameters("The profunctor value to transform.")]
324 #[document_returns("The transformed profunctor value.")]
325 #[document_examples]
326 ///
327 /// ```
328 /// use fp_library::{
329 /// Apply,
330 /// brands::*,
331 /// classes::{
332 /// Applicative,
333 /// lift::Lift,
334 /// optics::{
335 /// traversal::TraversalFunc,
336 /// *,
337 /// },
338 /// pointed::Pointed,
339 /// profunctor::*,
340 /// },
341 /// kinds::*,
342 /// types::optics::Traversal,
343 /// };
344 ///
345 /// #[derive(Clone)]
346 /// struct ListTraversal;
347 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
348 /// fn apply<M: Applicative>(
349 /// &self,
350 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
351 /// s: Vec<A>,
352 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
353 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
354 /// M::lift2(
355 /// |mut v: Vec<A>, x: A| {
356 /// v.push(x);
357 /// v
358 /// },
359 /// acc,
360 /// f(a),
361 /// )
362 /// })
363 /// }
364 /// }
365 ///
366 /// let traversal = Traversal::<'_, RcBrand, Vec<i32>, Vec<i32>, i32, i32, _>::new(ListTraversal);
367 /// let f = std::rc::Rc::new(|x: i32| x + 1) as std::rc::Rc<dyn Fn(i32) -> i32>;
368 /// let result: std::rc::Rc<dyn Fn(Vec<i32>) -> Vec<i32>> =
369 /// TraversalOptic::evaluate::<RcFnBrand>(&traversal, f);
370 /// assert_eq!(result(vec![1, 2]), vec![2, 3]);
371 /// ```
372 fn evaluate<Q: Wander>(
373 &self,
374 pab: Apply!(<Q as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, A, B>),
375 ) -> Apply!(<Q as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, S, T>) {
376 Optic::<Q, S, T, A, B>::evaluate(self, pab)
377 }
378 }
379
380 #[document_type_parameters(
381 "The lifetime of the values.",
382 "The reference-counted pointer type.",
383 "The source type of the structure.",
384 "The source type of the focus.",
385 "The type of the traversal function."
386 )]
387 #[document_parameters("The traversal instance.")]
388 impl<'a, PointerBrand, S, A, F> FoldOptic<'a, S, A> for Traversal<'a, PointerBrand, S, S, A, A, F>
389 where
390 PointerBrand: ToDynCloneFn,
391 F: TraversalFunc<'a, S, S, A, A> + Clone + 'a,
392 S: 'a,
393 A: 'a + Clone,
394 {
395 #[document_signature]
396 #[document_type_parameters(
397 "The monoid type.",
398 "The reference-counted pointer type for the Forget brand."
399 )]
400 #[document_parameters("The profunctor value to transform.")]
401 #[document_returns("The transformed profunctor value.")]
402 #[document_examples]
403 ///
404 /// ```
405 /// use fp_library::{
406 /// Apply,
407 /// brands::{
408 /// optics::*,
409 /// *,
410 /// },
411 /// classes::{
412 /// Applicative,
413 /// lift::Lift,
414 /// optics::{
415 /// traversal::TraversalFunc,
416 /// *,
417 /// },
418 /// pointed::Pointed,
419 /// profunctor::*,
420 /// },
421 /// kinds::*,
422 /// types::optics::{
423 /// Forget,
424 /// Traversal,
425 /// },
426 /// };
427 ///
428 /// #[derive(Clone)]
429 /// struct ListTraversal;
430 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
431 /// fn apply<M: Applicative>(
432 /// &self,
433 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
434 /// s: Vec<A>,
435 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
436 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
437 /// M::lift2(
438 /// |mut v: Vec<A>, x: A| {
439 /// v.push(x);
440 /// v
441 /// },
442 /// acc,
443 /// f(a),
444 /// )
445 /// })
446 /// }
447 /// }
448 ///
449 /// let traversal = Traversal::<'_, RcBrand, Vec<i32>, Vec<i32>, i32, i32, _>::new(ListTraversal);
450 /// let f = Forget::<RcBrand, String, i32, i32>::new(|x: i32| x.to_string());
451 /// let result = FoldOptic::evaluate(&traversal, f);
452 /// assert_eq!(result.run(vec![1, 2]), "12".to_string());
453 /// ```
454 fn evaluate<R: 'a + Monoid + Clone + 'static, Q: ToDynCloneFn + 'static>(
455 &self,
456 pab: Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, A, A>),
457 ) -> Apply!(<ForgetBrand<Q, R> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, S, S>)
458 {
459 TraversalOptic::evaluate::<ForgetBrand<Q, R>>(self, pab)
460 }
461 }
462
463 #[document_type_parameters(
464 "The lifetime of the values.",
465 "The reference-counted pointer type for the setter brand.",
466 "The reference-counted pointer type for the traversal.",
467 "The source type of the structure.",
468 "The target type of the structure after an update.",
469 "The source type of the focus.",
470 "The target type of the focus after an update.",
471 "The type of the traversal function."
472 )]
473 #[document_parameters("The traversal instance.")]
474 impl<'a, Q, PointerBrand, S, T, A, B, F> SetterOptic<'a, Q, S, T, A, B>
475 for Traversal<'a, PointerBrand, S, T, A, B, F>
476 where
477 PointerBrand: ToDynCloneFn,
478 Q: ToDynCloneFn,
479 F: TraversalFunc<'a, S, T, A, B> + Clone + 'a,
480 S: 'a,
481 T: 'a,
482 A: 'a,
483 B: 'a + Clone,
484 {
485 #[document_signature]
486 #[document_parameters("The profunctor value to transform.")]
487 #[document_returns("The transformed profunctor value.")]
488 #[document_examples]
489 ///
490 /// ```
491 /// use fp_library::{
492 /// Apply,
493 /// brands::*,
494 /// classes::{
495 /// Applicative,
496 /// lift::Lift,
497 /// optics::{
498 /// traversal::TraversalFunc,
499 /// *,
500 /// },
501 /// pointed::Pointed,
502 /// profunctor::*,
503 /// },
504 /// kinds::*,
505 /// types::optics::Traversal,
506 /// };
507 ///
508 /// #[derive(Clone)]
509 /// struct ListTraversal;
510 /// impl<'a, A: 'a + Clone> TraversalFunc<'a, Vec<A>, Vec<A>, A, A> for ListTraversal {
511 /// fn apply<M: Applicative>(
512 /// &self,
513 /// f: Box<dyn Fn(A) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, A>) + 'a>,
514 /// s: Vec<A>,
515 /// ) -> Apply!(<M as Kind!( type Of<'b, U: 'b>: 'b; )>::Of<'a, Vec<A>>) {
516 /// s.into_iter().fold(M::pure(vec![]), |acc, a| {
517 /// M::lift2(
518 /// |mut v: Vec<A>, x: A| {
519 /// v.push(x);
520 /// v
521 /// },
522 /// acc,
523 /// f(a),
524 /// )
525 /// })
526 /// }
527 /// }
528 ///
529 /// let traversal = Traversal::<'_, RcBrand, Vec<i32>, Vec<i32>, i32, i32, _>::new(ListTraversal);
530 /// let f = std::rc::Rc::new(|x: i32| x + 1) as std::rc::Rc<dyn Fn(i32) -> i32>;
531 /// let result: std::rc::Rc<dyn Fn(Vec<i32>) -> Vec<i32>> =
532 /// SetterOptic::<RcBrand, _, _, _, _>::evaluate(&traversal, f);
533 /// assert_eq!(result(vec![1, 2]), vec![2, 3]);
534 /// ```
535 fn evaluate(
536 &self,
537 pab: Apply!(<FnBrand<Q> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, A, B>),
538 ) -> Apply!(<FnBrand<Q> as Kind!( type Of<'b, T: 'b, U: 'b>: 'b; )>::Of<'a, S, T>) {
539 TraversalOptic::evaluate::<FnBrand<Q>>(self, pab)
540 }
541 }
542}
543pub use inner::*;