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}