fp_library/classes/
filterable.rs

1//! Filterable type class.
2//!
3//! This module defines the [`Filterable`] trait, which represents data structures that can be filtered and partitioned.
4
5use crate::{
6	Apply,
7	classes::{compactable::Compactable, functor::Functor},
8	kinds::*,
9	types::Pair,
10};
11
12/// A type class for data structures that can be filtered and partitioned.
13///
14/// `Filterable` extends [`Compactable`] and [`Functor`], adding methods for:
15/// *   `filter`: Keeping elements that satisfy a predicate.
16/// *   `filter_map`: Mapping and filtering in one step.
17/// *   `partition`: Splitting elements based on a predicate.
18/// *   `partition_map`: Mapping and partitioning in one step.
19pub trait Filterable: Compactable + Functor {
20	/// Partitions a data structure based on a function that returns a `Result`.
21	///
22	/// The default implementation uses [`Functor::map`] and [`Compactable::separate`].
23	///
24	/// ### Type Signature
25	///
26	/// `forall a e o f. Filterable f => (a -> Result o e) -> f a -> (f o, f e)`
27	///
28	/// ### Type Parameters
29	///
30	/// * `Func`: The type of the function to apply.
31	/// * `A`: The type of the elements in the input structure.
32	/// * `E`: The type of the error values.
33	/// * `O`: The type of the success values.
34	///
35	/// ### Parameters
36	///
37	/// * `func`: The function to apply to each element, returning a `Result`.
38	/// * `fa`: The data structure to partition.
39	///
40	/// ### Returns
41	///
42	/// A pair of data structures: the first containing the `Ok` values, and the second containing the `Err` values.
43	///
44	/// ### Examples
45	///
46	/// ```
47	/// use fp_library::classes::filterable::Filterable;
48	/// use fp_library::brands::OptionBrand;
49	/// use fp_library::types::Pair;
50	///
51	/// let x = Some(5);
52	/// let Pair(oks, errs) = OptionBrand::partition_map(|a| if a > 2 { Ok(a) } else { Err(a) }, x);
53	/// assert_eq!(oks, Some(5));
54	/// assert_eq!(errs, None);
55	/// ```
56	fn partition_map<'a, Func, A: 'a, E: 'a, O: 'a>(
57		func: Func,
58		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
59	) -> Pair<
60		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
61		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
62	>
63	where
64		Func: Fn(A) -> Result<O, E> + 'a,
65	{
66		Self::separate(Self::map(func, fa))
67	}
68
69	/// Partitions a data structure based on a predicate.
70	///
71	/// The default implementation uses [`partition_map`].
72	///
73	/// **Note**: The return order is `(satisfied, not_satisfied)`, matching Rust's `Iterator::partition`.
74	/// This is achieved by mapping satisfied elements to `Ok` and unsatisfied elements to `Err` internally,
75	/// as `separate` returns `(Oks, Errs)`.
76	///
77	/// ### Type Signature
78	///
79	/// `forall a f. Filterable f => (a -> bool) -> f a -> (f a, f a)`
80	///
81	/// ### Type Parameters
82	///
83	/// * `Func`: The type of the predicate function.
84	/// * `A`: The type of the elements in the structure.
85	///
86	/// ### Parameters
87	///
88	/// * `func`: The predicate function.
89	/// * `fa`: The data structure to partition.
90	///
91	/// ### Returns
92	///
93	/// A pair of data structures: the first containing elements that satisfy the predicate, and the second containing elements that do not.
94	///
95	/// ### Examples
96	///
97	/// ```
98	/// use fp_library::classes::filterable::Filterable;
99	/// use fp_library::brands::OptionBrand;
100	/// use fp_library::types::Pair;
101	///
102	/// let x = Some(5);
103	/// let Pair(satisfied, not_satisfied) = OptionBrand::partition(|a| a > 2, x);
104	/// assert_eq!(satisfied, Some(5));
105	/// assert_eq!(not_satisfied, None);
106	/// ```
107	fn partition<'a, Func, A: 'a + Clone>(
108		func: Func,
109		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
110	) -> Pair<
111		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
112		Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
113	>
114	where
115		Func: Fn(A) -> bool + 'a,
116	{
117		Self::partition_map(move |a| if func(a.clone()) { Ok(a) } else { Err(a) }, fa)
118	}
119
120	/// Maps a function over a data structure and filters out `None` results.
121	///
122	/// The default implementation uses [`Functor::map`] and [`Compactable::compact`].
123	///
124	/// ### Type Signature
125	///
126	/// `forall a b f. Filterable f => (a -> Option b) -> f a -> f b`
127	///
128	/// ### Type Parameters
129	///
130	/// * `Func`: The type of the function to apply.
131	/// * `A`: The type of the elements in the input structure.
132	/// * `B`: The type of the elements in the output structure.
133	///
134	/// ### Parameters
135	///
136	/// * `func`: The function to apply to each element, returning an `Option`.
137	/// * `fa`: The data structure to filter and map.
138	///
139	/// ### Returns
140	///
141	/// A new data structure containing only the values where the function returned `Some`.
142	///
143	/// ### Examples
144	///
145	/// ```
146	/// use fp_library::classes::filterable::Filterable;
147	/// use fp_library::brands::OptionBrand;
148	///
149	/// let x = Some(5);
150	/// let y = OptionBrand::filter_map(|a| if a > 2 { Some(a * 2) } else { None }, x);
151	/// assert_eq!(y, Some(10));
152	/// ```
153	fn filter_map<'a, Func, A: 'a, B: 'a>(
154		func: Func,
155		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
156	) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
157	where
158		Func: Fn(A) -> Option<B> + 'a,
159	{
160		Self::compact(Self::map(func, fa))
161	}
162
163	/// Filters a data structure based on a predicate.
164	///
165	/// The default implementation uses [`filter_map`].
166	///
167	/// ### Type Signature
168	///
169	/// `forall a f. Filterable f => (a -> bool) -> f a -> f a`
170	///
171	/// ### Type Parameters
172	///
173	/// * `Func`: The type of the predicate function.
174	/// * `A`: The type of the elements in the structure.
175	///
176	/// ### Parameters
177	///
178	/// * `func`: The predicate function.
179	/// * `fa`: The data structure to filter.
180	///
181	/// ### Returns
182	///
183	/// A new data structure containing only the elements that satisfy the predicate.
184	///
185	/// ### Examples
186	///
187	/// ```
188	/// use fp_library::classes::filterable::Filterable;
189	/// use fp_library::brands::OptionBrand;
190	///
191	/// let x = Some(5);
192	/// let y = OptionBrand::filter(|a| a > 2, x);
193	/// assert_eq!(y, Some(5));
194	/// ```
195	fn filter<'a, Func, A: 'a + Clone>(
196		func: Func,
197		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
198	) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
199	where
200		Func: Fn(A) -> bool + 'a,
201	{
202		Self::filter_map(move |a| if func(a.clone()) { Some(a) } else { None }, fa)
203	}
204}
205
206/// Partitions a data structure based on a function that returns a `Result`.
207///
208/// Free function version that dispatches to [the type class' associated function][`Filterable::partition_map`].
209///
210/// ### Type Signature
211///
212/// `forall a e o f. Filterable f => (a -> Result o e) -> f a -> (f o, f e)`
213///
214/// ### Type Parameters
215///
216/// * `Brand`: The brand of the filterable structure.
217/// * `Func`: The type of the function to apply.
218/// * `A`: The type of the elements in the input structure.
219/// * `E`: The type of the error values.
220/// * `O`: The type of the success values.
221///
222/// ### Parameters
223///
224/// * `func`: The function to apply to each element, returning a `Result`.
225/// * `fa`: The data structure to partition.
226///
227/// ### Returns
228///
229/// A pair of data structures: the first containing the `Ok` values, and the second containing the `Err` values.
230///
231/// ### Examples
232///
233/// ```
234/// use fp_library::classes::filterable::partition_map;
235/// use fp_library::brands::OptionBrand;
236/// use fp_library::types::Pair;
237///
238/// let x = Some(5);
239/// let Pair(oks, errs) = partition_map::<OptionBrand, _, _, _, _>(|a| if a > 2 { Ok(a) } else { Err(a) }, x);
240/// assert_eq!(oks, Some(5));
241/// assert_eq!(errs, None);
242/// ```
243pub fn partition_map<'a, Brand: Filterable, Func, A: 'a, E: 'a, O: 'a>(
244	func: Func,
245	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
246) -> Pair<
247	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
248	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
249>
250where
251	Func: Fn(A) -> Result<O, E> + 'a,
252{
253	Brand::partition_map(func, fa)
254}
255
256/// Partitions a data structure based on a predicate.
257///
258/// Free function version that dispatches to [the type class' associated function][`Filterable::partition`].
259///
260/// **Note**: The return order is `(satisfied, not_satisfied)`, matching Rust's `Iterator::partition`.
261///
262/// ### Type Signature
263///
264/// `forall a f. Filterable f => (a -> bool) -> f a -> (f a, f a)`
265///
266/// ### Type Parameters
267///
268/// * `Brand`: The brand of the filterable structure.
269/// * `Func`: The type of the predicate function.
270/// * `A`: The type of the elements in the structure.
271///
272/// ### Parameters
273///
274/// * `func`: The predicate function.
275/// * `fa`: The data structure to partition.
276///
277/// ### Returns
278///
279/// A pair of data structures: the first containing elements that satisfy the predicate, and the second containing elements that do not.
280///
281/// ### Examples
282///
283/// ```
284/// use fp_library::classes::filterable::partition;
285/// use fp_library::brands::OptionBrand;
286/// use fp_library::types::Pair;
287///
288/// let x = Some(5);
289/// let Pair(satisfied, not_satisfied) = partition::<OptionBrand, _, _>(|a| a > 2, x);
290/// assert_eq!(satisfied, Some(5));
291/// assert_eq!(not_satisfied, None);
292/// ```
293pub fn partition<'a, Brand: Filterable, Func, A: 'a + Clone>(
294	func: Func,
295	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
296) -> Pair<
297	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
298	Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
299>
300where
301	Func: Fn(A) -> bool + 'a,
302{
303	Brand::partition(func, fa)
304}
305
306/// Maps a function over a data structure and filters out `None` results.
307///
308/// Free function version that dispatches to [the type class' associated function][`Filterable::filter_map`].
309///
310/// ### Type Signature
311///
312/// `forall a b f. Filterable f => (a -> Option b) -> f a -> f b`
313///
314/// ### Type Parameters
315///
316/// * `Brand`: The brand of the filterable structure.
317/// * `Func`: The type of the function to apply.
318/// * `A`: The type of the elements in the input structure.
319/// * `B`: The type of the elements in the output structure.
320///
321/// ### Parameters
322///
323/// * `func`: The function to apply to each element, returning an `Option`.
324/// * `fa`: The data structure to filter and map.
325///
326/// ### Returns
327///
328/// A new data structure containing only the values where the function returned `Some`.
329///
330/// ### Examples
331///
332/// ```
333/// use fp_library::classes::filterable::filter_map;
334/// use fp_library::brands::OptionBrand;
335///
336/// let x = Some(5);
337/// let y = filter_map::<OptionBrand, _, _, _>(|a| if a > 2 { Some(a * 2) } else { None }, x);
338/// assert_eq!(y, Some(10));
339/// ```
340pub fn filter_map<'a, Brand: Filterable, Func, A: 'a, B: 'a>(
341	func: Func,
342	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
343) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
344where
345	Func: Fn(A) -> Option<B> + 'a,
346{
347	Brand::filter_map(func, fa)
348}
349
350/// Filters a data structure based on a predicate.
351///
352/// Free function version that dispatches to [the type class' associated function][`Filterable::filter`].
353///
354/// ### Type Signature
355///
356/// `forall a f. Filterable f => (a -> bool) -> f a -> f a`
357///
358/// ### Type Parameters
359///
360/// * `Brand`: The brand of the filterable structure.
361/// * `Func`: The type of the predicate function.
362/// * `A`: The type of the elements in the structure.
363///
364/// ### Parameters
365///
366/// * `func`: The predicate function.
367/// * `fa`: The data structure to filter.
368///
369/// ### Returns
370///
371/// A new data structure containing only the elements that satisfy the predicate.
372///
373/// ### Examples
374///
375/// ```
376/// use fp_library::classes::filterable::filter;
377/// use fp_library::brands::OptionBrand;
378///
379/// let x = Some(5);
380/// let y = filter::<OptionBrand, _, _>(|a| a > 2, x);
381/// assert_eq!(y, Some(5));
382/// ```
383pub fn filter<'a, Brand: Filterable, Func, A: 'a + Clone>(
384	func: Func,
385	fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
386) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)
387where
388	Func: Fn(A) -> bool + 'a,
389{
390	Brand::filter(func, fa)
391}