Skip to main content

fp_library/classes/
ref_witherable.rs

1//! By-reference withering (effectful filtering) of structures.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! 	brands::*,
8//! 	functions::explicit::*,
9//! };
10//!
11//! let v = vec![1, 2, 3, 4, 5];
12//! let result: Option<Vec<i32>> = wither::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _>(
13//! 	|x: &i32| if *x > 3 { Some(Some(*x)) } else { Some(None) },
14//! 	&v,
15//! );
16//! assert_eq!(result, Some(vec![4, 5]));
17//! ```
18
19#[fp_macros::document_module]
20mod inner {
21	use {
22		crate::{
23			classes::*,
24			kinds::*,
25		},
26		fp_macros::*,
27	};
28
29	/// By-reference withering (effectful filtering) of structures.
30	///
31	/// Similar to [`Witherable`], but closures receive `&A` instead of `A`.
32	/// Combines by-reference traversal with filtering in an applicative context.
33	///
34	/// Default implementations derive:
35	/// * `ref_wilt` from `ref_traverse` + `separate`.
36	/// * `ref_wither` from `ref_traverse` + `compact`.
37	#[kind(type Of<'a, A: 'a>: 'a;)]
38	pub trait RefWitherable: RefFilterable + RefTraversable {
39		/// Partitions by reference in an applicative context.
40		///
41		/// Maps each element by reference to a computation producing `Result<O, E>`,
42		/// traverses the structure, then separates the results.
43		#[document_signature]
44		///
45		#[document_type_parameters(
46			"The lifetime of the elements.",
47			"The brand of the cloneable function wrapper.",
48			"The applicative context.",
49			"The type of the input elements.",
50			"The error type.",
51			"The success type."
52		)]
53		///
54		#[document_parameters(
55			"The function to apply to each element reference.",
56			"The structure to partition."
57		)]
58		///
59		#[document_returns("The partitioned structure in the applicative context.")]
60		#[document_examples]
61		///
62		/// ```
63		/// use fp_library::{
64		/// 	brands::*,
65		/// 	functions::explicit::*,
66		/// };
67		///
68		/// let v = vec![1, 2, 3, 4, 5];
69		/// let result: Option<(Vec<i32>, Vec<i32>)> =
70		/// 	wilt::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _, _>(
71		/// 		|x: &i32| Some(if *x > 3 { Ok(*x) } else { Err(*x) }),
72		/// 		&v,
73		/// 	);
74		/// assert_eq!(result, Some((vec![1, 2, 3], vec![4, 5])));
75		/// ```
76		fn ref_wilt<'a, FnBrand, M: Applicative, A: 'a + Clone, E: 'a + Clone, O: 'a + Clone>(
77			func: impl Fn(&A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
78			+ 'a,
79			ta: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
80		) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
81			'a,
82			(
83				Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
84				Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
85			),
86		>)
87		where
88			FnBrand: LiftFn + 'a,
89			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
90			Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone, {
91			M::map(
92				|res| Self::separate::<E, O>(res),
93				Self::ref_traverse::<FnBrand, A, Result<O, E>, M>(func, ta),
94			)
95		}
96
97		/// Filters by reference in an applicative context.
98		///
99		/// Maps each element by reference to a computation producing `Option<B>`,
100		/// traverses the structure, then compacts the results.
101		#[document_signature]
102		///
103		#[document_type_parameters(
104			"The lifetime of the elements.",
105			"The brand of the cloneable function wrapper.",
106			"The applicative context.",
107			"The type of the input elements.",
108			"The type of the output elements."
109		)]
110		///
111		#[document_parameters(
112			"The function to apply to each element reference.",
113			"The structure to filter."
114		)]
115		///
116		#[document_returns("The filtered structure in the applicative context.")]
117		#[document_examples]
118		///
119		/// ```
120		/// use fp_library::{
121		/// 	brands::*,
122		/// 	functions::explicit::*,
123		/// };
124		///
125		/// let v = vec![1, 2, 3, 4, 5];
126		/// let result: Option<Vec<i32>> = wither::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _>(
127		/// 	|x: &i32| if *x > 3 { Some(Some(*x)) } else { Some(None) },
128		/// 	&v,
129		/// );
130		/// assert_eq!(result, Some(vec![4, 5]));
131		/// ```
132		fn ref_wither<'a, FnBrand, M: Applicative, A: 'a + Clone, B: 'a + Clone>(
133			func: impl Fn(&A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>) + 'a,
134			ta: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
135		) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
136			'a,
137			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
138		>)
139		where
140			FnBrand: LiftFn + 'a,
141			Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
142			Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone, {
143			M::map(
144				|opt| Self::compact(opt),
145				Self::ref_traverse::<FnBrand, A, Option<B>, M>(func, ta),
146			)
147		}
148	}
149
150	/// Partitions by reference in an applicative context.
151	///
152	/// Free function version that dispatches to [the type class' associated function][`RefWitherable::ref_wilt`].
153	#[document_signature]
154	///
155	#[document_type_parameters(
156		"The lifetime of the elements.",
157		"The brand of the structure.",
158		"The brand of the cloneable function wrapper.",
159		"The applicative context.",
160		"The type of the input elements.",
161		"The error type.",
162		"The success type."
163	)]
164	///
165	#[document_parameters(
166		"The function to apply to each element reference.",
167		"The structure to partition."
168	)]
169	///
170	#[document_returns("The partitioned structure in the applicative context.")]
171	#[document_examples]
172	///
173	/// ```
174	/// use fp_library::{
175	/// 	brands::*,
176	/// 	functions::explicit::*,
177	/// };
178	///
179	/// let v = vec![1, 2, 3, 4, 5];
180	/// let result: Option<(Vec<i32>, Vec<i32>)> =
181	/// 	wilt::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _, _>(
182	/// 		|x: &i32| Some(if *x > 3 { Ok(*x) } else { Err(*x) }),
183	/// 		&v,
184	/// 	);
185	/// assert_eq!(result, Some((vec![1, 2, 3], vec![4, 5])));
186	/// ```
187	pub fn ref_wilt<
188		'a,
189		Brand: RefWitherable,
190		FnBrand,
191		M: Applicative,
192		A: 'a + Clone,
193		E: 'a + Clone,
194		O: 'a + Clone,
195	>(
196		func: impl Fn(&A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>) + 'a,
197		ta: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
198	) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
199		'a,
200		(
201			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
202			Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
203		),
204	>)
205	where
206		FnBrand: LiftFn + 'a,
207		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
208		Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone, {
209		Brand::ref_wilt::<FnBrand, M, A, E, O>(func, ta)
210	}
211
212	/// Filters by reference in an applicative context.
213	///
214	/// Free function version that dispatches to [the type class' associated function][`RefWitherable::ref_wither`].
215	#[document_signature]
216	///
217	#[document_type_parameters(
218		"The lifetime of the elements.",
219		"The brand of the structure.",
220		"The brand of the cloneable function wrapper.",
221		"The applicative context.",
222		"The type of the input elements.",
223		"The type of the output elements."
224	)]
225	///
226	#[document_parameters(
227		"The function to apply to each element reference.",
228		"The structure to filter."
229	)]
230	///
231	#[document_returns("The filtered structure in the applicative context.")]
232	#[document_examples]
233	///
234	/// ```
235	/// use fp_library::{
236	/// 	brands::*,
237	/// 	functions::explicit::*,
238	/// };
239	///
240	/// let v = vec![1, 2, 3, 4, 5];
241	/// let result: Option<Vec<i32>> = wither::<RcFnBrand, VecBrand, OptionBrand, _, _, _, _>(
242	/// 	|x: &i32| if *x > 3 { Some(Some(*x)) } else { Some(None) },
243	/// 	&v,
244	/// );
245	/// assert_eq!(result, Some(vec![4, 5]));
246	/// ```
247	pub fn ref_wither<
248		'a,
249		Brand: RefWitherable,
250		FnBrand,
251		M: Applicative,
252		A: 'a + Clone,
253		B: 'a + Clone,
254	>(
255		func: impl Fn(&A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>) + 'a,
256		ta: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
257	) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
258		'a,
259		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
260	>)
261	where
262		FnBrand: LiftFn + 'a,
263		Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
264		Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone, {
265		Brand::ref_wither::<FnBrand, M, A, B>(func, ta)
266	}
267}
268
269pub use inner::*;