fp_library/classes/witherable.rs
1//! Witherable type class.
2//!
3//! This module defines the [`Witherable`] trait, which represents data structures that can be traversed and filtered in an applicative context.
4
5use crate::{
6 Apply,
7 classes::{applicative::Applicative, filterable::Filterable, traversable::Traversable},
8 kinds::*,
9 types::Pair,
10};
11
12/// A type class for data structures that can be traversed and filtered.
13///
14/// `Witherable` extends [`Filterable`] and [`Traversable`], adding methods for:
15/// * `wither`: Effectful `filter_map`.
16/// * `wilt`: Effectful `partition_map`.
17pub trait Witherable: Filterable + Traversable {
18 /// Partitions a data structure based on a function that returns a `Result` in an applicative context.
19 ///
20 /// The default implementation uses [`Traversable::traverse`] and [`Compactable::separate`](crate::classes::compactable::Compactable::separate).
21 ///
22 /// ### Type Signature
23 ///
24 /// `forall a e o m f. (Witherable f, Applicative m) => (a -> m (Result o e)) -> f a -> m (f o, f e)`
25 ///
26 /// ### Type Parameters
27 ///
28 /// * `Func`: The type of the function to apply.
29 /// * `M`: The applicative context.
30 /// * `A`: The type of the elements in the input structure.
31 /// * `E`: The type of the error values.
32 /// * `O`: The type of the success values.
33 ///
34 /// ### Parameters
35 ///
36 /// * `func`: The function to apply to each element, returning a `Result` in an applicative context.
37 /// * `ta`: The data structure to partition.
38 ///
39 /// ### Returns
40 ///
41 /// The partitioned data structure wrapped in the applicative context.
42 ///
43 /// ### Examples
44 ///
45 /// ```
46 /// use fp_library::classes::witherable::Witherable;
47 /// use fp_library::brands::OptionBrand;
48 /// use fp_library::types::Pair;
49 ///
50 /// let x = Some(5);
51 /// let y = OptionBrand::wilt::<_, OptionBrand, _, _, _>(|a| Some(if a > 2 { Ok(a) } else { Err(a) }), x);
52 /// assert_eq!(y, Some(Pair(Some(5), None)));
53 /// ```
54 fn wilt<'a, Func, M: Applicative, A: 'a + Clone, E: 'a + Clone, O: 'a + Clone>(
55 func: Func,
56 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
57 ) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
58 '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 >)
64 where
65 Func: Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>) + 'a,
66 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
67 Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
68 {
69 M::map(|res| Self::separate(res), Self::traverse::<M, Func, A, Result<O, E>>(func, ta))
70 }
71
72 /// Maps a function over a data structure and filters out `None` results in an applicative context.
73 ///
74 /// The default implementation uses [`Traversable::traverse`] and [`Compactable::compact`](crate::classes::compactable::Compactable::compact).
75 ///
76 /// ### Type Signature
77 ///
78 /// `forall a b m f. (Witherable f, Applicative m) => (a -> m (Option b)) -> f a -> m (f b)`
79 ///
80 /// ### Type Parameters
81 ///
82 /// * `Func`: The type of the function to apply.
83 /// * `M`: The applicative context.
84 /// * `A`: The type of the elements in the input structure.
85 /// * `B`: The type of the elements in the output structure.
86 ///
87 /// ### Parameters
88 ///
89 /// * `func`: The function to apply to each element, returning an `Option` in an applicative context.
90 /// * `ta`: The data structure to filter and map.
91 ///
92 /// ### Returns
93 ///
94 /// The filtered and mapped data structure wrapped in the applicative context.
95 ///
96 /// ### Examples
97 ///
98 /// ```
99 /// use fp_library::classes::witherable::Witherable;
100 /// use fp_library::brands::OptionBrand;
101 ///
102 /// let x = Some(5);
103 /// let y = OptionBrand::wither::<_, OptionBrand, _, _>(|a| Some(if a > 2 { Some(a * 2) } else { None }), x);
104 /// assert_eq!(y, Some(Some(10)));
105 /// ```
106 fn wither<'a, Func, M: Applicative, A: 'a + Clone, B: 'a + Clone>(
107 func: Func,
108 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
109 ) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
110 'a,
111 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
112 >)
113 where
114 Func: Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>) + 'a,
115 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
116 Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
117 {
118 M::map(|opt| Self::compact(opt), Self::traverse::<M, Func, A, Option<B>>(func, ta))
119 }
120}
121
122/// Partitions a data structure based on a function that returns a `Result` in an applicative context.
123///
124/// Free function version that dispatches to [the type class' associated function][`Witherable::wilt`].
125///
126/// ### Type Signature
127///
128/// `forall a e o m f. (Witherable f, Applicative m) => (a -> m (Result o e)) -> f a -> m (f o, f e)`
129///
130/// ### Type Parameters
131///
132/// * `Brand`: The brand of the witherable structure.
133/// * `Func`: The type of the function to apply.
134/// * `M`: The applicative context.
135/// * `A`: The type of the elements in the input structure.
136/// * `E`: The type of the error values.
137/// * `O`: The type of the success values.
138///
139/// ### Parameters
140///
141/// * `func`: The function to apply to each element, returning a `Result` in an applicative context.
142/// * `ta`: The data structure to partition.
143///
144/// ### Returns
145///
146/// The partitioned data structure wrapped in the applicative context.
147///
148/// ### Examples
149///
150/// ```
151/// use fp_library::classes::witherable::wilt;
152/// use fp_library::brands::OptionBrand;
153/// use fp_library::types::Pair;
154///
155/// let x = Some(5);
156/// let y = wilt::<OptionBrand, _, OptionBrand, _, _, _>(|a| Some(if a > 2 { Ok(a) } else { Err(a) }), x);
157/// assert_eq!(y, Some(Pair(Some(5), None)));
158/// ```
159pub fn wilt<
160 'a,
161 Brand: Witherable,
162 Func,
163 M: Applicative,
164 A: 'a + Clone,
165 E: 'a + Clone,
166 O: 'a + Clone,
167>(
168 func: Func,
169 ta: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
170) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
171 'a,
172 Pair<
173 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
174 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
175 >,
176>)
177where
178 Func: Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>) + 'a,
179 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
180 Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>): Clone,
181{
182 Brand::wilt::<_, M, _, _, _>(func, ta)
183}
184
185/// Maps a function over a data structure and filters out `None` results in an applicative context.
186///
187/// Free function version that dispatches to [the type class' associated function][`Witherable::wither`].
188///
189/// ### Type Signature
190///
191/// `forall a b m f. (Witherable f, Applicative m) => (a -> m (Option b)) -> f a -> m (f b)`
192///
193/// ### Type Parameters
194///
195/// * `Brand`: The brand of the witherable structure.
196/// * `Func`: The type of the function to apply.
197/// * `M`: The applicative context.
198/// * `A`: The type of the elements in the input structure.
199/// * `B`: The type of the elements in the output structure.
200///
201/// ### Parameters
202///
203/// * `func`: The function to apply to each element, returning an `Option` in an applicative context.
204/// * `ta`: The data structure to filter and map.
205///
206/// ### Returns
207///
208/// The filtered and mapped data structure wrapped in the applicative context.
209///
210/// ### Examples
211///
212/// ```
213/// use fp_library::classes::witherable::wither;
214/// use fp_library::brands::OptionBrand;
215///
216/// let x = Some(5);
217/// let y = wither::<OptionBrand, _, OptionBrand, _, _>(|a| Some(if a > 2 { Some(a * 2) } else { None }), x);
218/// assert_eq!(y, Some(Some(10)));
219/// ```
220pub fn wither<'a, Brand: Witherable, Func, M: Applicative, A: 'a + Clone, B: 'a + Clone>(
221 func: Func,
222 ta: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
223) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
224 'a,
225 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
226>)
227where
228 Func: Fn(A) -> Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>) + 'a,
229 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
230 Apply!(<M as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Option<B>>): Clone,
231{
232 Brand::wither::<_, M, _, _>(func, ta)
233}