Skip to main content

fp_library/classes/
ref_traversable.rs

1//! By-reference traversal of structures.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! 	brands::*,
8//! 	functions::*,
9//! };
10//!
11//! let v = vec![1, 2, 3];
12//! let result: Option<Vec<String>> =
13//! 	ref_traverse::<VecBrand, RcFnBrand, _, _, OptionBrand>(|x: &i32| Some(x.to_string()), &v);
14//! assert_eq!(result, Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]));
15//! ```
16
17#[fp_macros::document_module]
18mod inner {
19	use {
20		crate::{
21			classes::*,
22			kinds::*,
23		},
24		fp_macros::*,
25	};
26
27	/// By-reference traversal of structures.
28	///
29	/// Similar to [`Traversable`], but the closure receives `&A` instead of `A`.
30	/// This enables traversing collections by reference without consuming elements,
31	/// or traversing memoized types that only provide `&A` access.
32	///
33	/// `ref_traverse` is the required method.
34	#[kind(type Of<'a, A: 'a>: 'a;)]
35	pub trait RefTraversable: RefFunctor + RefFoldable {
36		/// Maps each element by reference to a computation, evaluates them,
37		/// and combines the results.
38		#[document_signature]
39		///
40		#[document_type_parameters(
41			"The lifetime of the elements.",
42			"The brand of the cloneable function wrapper.",
43			"The type of the elements in the input structure.",
44			"The type of the elements in the output structure.",
45			"The applicative functor brand for the computation."
46		)]
47		///
48		#[document_parameters(
49			"The function to apply to each element reference.",
50			"The structure to traverse."
51		)]
52		///
53		#[document_returns("The combined result in the applicative context.")]
54		#[document_examples]
55		///
56		/// ```
57		/// use fp_library::{
58		/// 	brands::*,
59		/// 	functions::*,
60		/// };
61		///
62		/// let v = vec![1, 2, 3];
63		/// let result: Option<Vec<String>> =
64		/// 	ref_traverse::<VecBrand, RcFnBrand, _, _, OptionBrand>(|x: &i32| Some(x.to_string()), &v);
65		/// assert_eq!(result, Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]));
66		/// ```
67		fn ref_traverse<'a, FnBrand, A: 'a + Clone, B: 'a + Clone, F: Applicative>(
68			func: impl Fn(&A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
69			ta: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
70		) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
71		where
72			FnBrand: LiftFn + 'a,
73			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone,
74			Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone;
75	}
76
77	/// Maps each element by reference to a computation, evaluates them,
78	/// and combines the results.
79	///
80	/// Free function version that dispatches to [the type class' associated function][`RefTraversable::ref_traverse`].
81	#[document_signature]
82	///
83	#[document_type_parameters(
84		"The lifetime of the elements.",
85		"The brand of the structure.",
86		"The brand of the cloneable function wrapper.",
87		"The type of the input elements.",
88		"The type of the output elements.",
89		"The applicative functor brand."
90	)]
91	///
92	#[document_parameters(
93		"The function to apply to each element reference.",
94		"The structure to traverse."
95	)]
96	///
97	#[document_returns("The combined result in the applicative context.")]
98	#[document_examples]
99	///
100	/// ```
101	/// use fp_library::{
102	/// 	brands::*,
103	/// 	functions::*,
104	/// };
105	///
106	/// let v = vec![1, 2, 3];
107	/// let result: Option<Vec<String>> =
108	/// 	ref_traverse::<VecBrand, RcFnBrand, _, _, OptionBrand>(|x: &i32| Some(x.to_string()), &v);
109	/// assert_eq!(result, Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]));
110	/// ```
111	pub fn ref_traverse<
112		'a,
113		Brand: RefTraversable,
114		FnBrand,
115		A: 'a + Clone,
116		B: 'a + Clone,
117		F: Applicative,
118	>(
119		func: impl Fn(&A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
120		ta: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
121	) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
122	where
123		FnBrand: LiftFn + 'a,
124		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone,
125		Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone, {
126		Brand::ref_traverse::<FnBrand, A, B, F>(func, ta)
127	}
128}
129
130pub use inner::*;