Skip to main content

fp_library/classes/
filterable.rs

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