fp_library/classes/compactable.rs
1//! Data structures that can be compacted by filtering out [`None`] or separated by splitting [`Result`] values.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! brands::*,
8//! functions::*,
9//! };
10//!
11//! let x = Some(Some(5));
12//! let y = compact::<OptionBrand, _>(x);
13//! assert_eq!(y, Some(5));
14//! ```
15
16#[fp_macros::document_module]
17mod inner {
18 use {
19 crate::{
20 brands::*,
21 kinds::*,
22 },
23 fp_macros::*,
24 };
25
26 /// A type class for data structures that can be compacted and separated.
27 ///
28 /// `Compactable` allows for:
29 /// * `compact`: Filtering out [`None`] values and unwrapping [`Some`] values from a structure of [`Option`]s.
30 /// * `separate`: Splitting a structure of [`Result`]s into a pair of structures, one containing the [`Err`] values and the other containing the [`Ok`] values.
31 ///
32 /// ### Laws
33 ///
34 /// To be `Compactable` alone, no laws must be satisfied other than the type signature.
35 ///
36 /// If the data type is also a [`Functor`](crate::classes::Functor):
37 /// * Identity: `compact(map(Some, fa)) = fa`.
38 ///
39 /// If the data type is also [`Plus`](crate::classes::Plus):
40 /// * Annihilation (empty): `compact(empty) = empty`.
41 /// * Annihilation (map): `compact(map(|_| None, xs)) = empty`.
42 #[document_examples]
43 ///
44 /// Compactable laws for [`Option`]:
45 ///
46 /// ```
47 /// use fp_library::{
48 /// brands::*,
49 /// functions::*,
50 /// };
51 ///
52 /// // Functor Identity: compact(map(Some, fa)) = fa
53 /// assert_eq!(compact::<OptionBrand, _>(map::<OptionBrand, _, _>(Some, Some(5))), Some(5),);
54 /// assert_eq!(compact::<OptionBrand, _>(map::<OptionBrand, _, _>(Some, None::<i32>)), None,);
55 ///
56 /// // Plus Annihilation (empty): compact(empty) = empty
57 /// assert_eq!(
58 /// compact::<OptionBrand, _>(plus_empty::<OptionBrand, Option<i32>>()),
59 /// plus_empty::<OptionBrand, i32>(),
60 /// );
61 ///
62 /// // Plus Annihilation (map): compact(map(|_| None, xs)) = empty
63 /// assert_eq!(
64 /// compact::<OptionBrand, _>(map::<OptionBrand, _, _>(|_: i32| None::<i32>, Some(5))),
65 /// plus_empty::<OptionBrand, i32>(),
66 /// );
67 /// ```
68 ///
69 /// Compactable laws for [`Vec`]:
70 ///
71 /// ```
72 /// use fp_library::{
73 /// brands::*,
74 /// functions::*,
75 /// };
76 ///
77 /// // Functor Identity: compact(map(Some, fa)) = fa
78 /// assert_eq!(compact::<VecBrand, _>(map::<VecBrand, _, _>(Some, vec![1, 2, 3])), vec![1, 2, 3],);
79 ///
80 /// // Plus Annihilation (empty): compact(empty) = empty
81 /// assert_eq!(
82 /// compact::<VecBrand, _>(plus_empty::<VecBrand, Option<i32>>()),
83 /// plus_empty::<VecBrand, i32>(),
84 /// );
85 ///
86 /// // Plus Annihilation (map): compact(map(|_| None, xs)) = empty
87 /// assert_eq!(
88 /// compact::<VecBrand, _>(map::<VecBrand, _, _>(|_: i32| None::<i32>, vec![1, 2, 3])),
89 /// plus_empty::<VecBrand, i32>(),
90 /// );
91 /// ```
92 pub trait Compactable: Kind_cdc7cd43dac7585f {
93 /// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
94 #[document_signature]
95 ///
96 #[document_type_parameters(
97 "The lifetime of the elements.",
98 "The type of the elements in the [`Option`]."
99 )]
100 ///
101 #[document_parameters("The data structure containing [`Option`] values.")]
102 ///
103 #[document_returns(
104 "A new data structure containing only the values from the [`Some`] variants."
105 )]
106 #[document_examples]
107 ///
108 /// ```
109 /// use fp_library::{
110 /// brands::*,
111 /// functions::*,
112 /// };
113 ///
114 /// let x = Some(Some(5));
115 /// let y = compact::<OptionBrand, _>(x);
116 /// assert_eq!(y, Some(5));
117 ///
118 /// let z = Some(None::<i32>);
119 /// let w = compact::<OptionBrand, _>(z);
120 /// assert_eq!(w, None);
121 /// ```
122 fn compact<'a, A: 'a>(
123 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
124 'a,
125 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
126 >)
127 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
128
129 /// Separates a data structure of [`Result`]s into two data structures: one containing the [`Err`] values and one containing the [`Ok`] values.
130 #[document_signature]
131 ///
132 #[document_type_parameters(
133 "The lifetime of the elements.",
134 "The type of the error values.",
135 "The type of the success values."
136 )]
137 ///
138 #[document_parameters("The data structure containing [`Result`] values.")]
139 ///
140 #[document_returns(
141 "A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values."
142 )]
143 #[document_examples]
144 ///
145 /// ```
146 /// use fp_library::{
147 /// brands::*,
148 /// functions::*,
149 /// };
150 ///
151 /// let x: Option<Result<i32, &str>> = Some(Ok(5));
152 /// let (errs, oks) = separate::<OptionBrand, _, _>(x);
153 /// assert_eq!(oks, Some(5));
154 /// assert_eq!(errs, None);
155 ///
156 /// let y: Option<Result<i32, &str>> = Some(Err("error"));
157 /// let (errs2, oks2) = separate::<OptionBrand, _, _>(y);
158 /// assert_eq!(oks2, None);
159 /// assert_eq!(errs2, Some("error"));
160 /// ```
161 fn separate<'a, E: 'a, O: 'a>(
162 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
163 ) -> (
164 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
165 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
166 );
167 }
168
169 /// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
170 ///
171 /// Free function version that dispatches to [the type class' associated function][`Compactable::compact`].
172 #[document_signature]
173 ///
174 #[document_type_parameters(
175 "The lifetime of the elements.",
176 "The brand of the compactable structure.",
177 "The type of the elements in the [`Option`]."
178 )]
179 ///
180 #[document_parameters("The data structure containing [`Option`] values.")]
181 ///
182 #[document_returns(
183 "A new data structure containing only the values from the [`Some`] variants."
184 )]
185 #[document_examples]
186 ///
187 /// ```
188 /// use fp_library::{
189 /// brands::*,
190 /// functions::*,
191 /// };
192 ///
193 /// let x = Some(Some(5));
194 /// let y = compact::<OptionBrand, _>(x);
195 /// assert_eq!(y, Some(5));
196 /// ```
197 pub fn compact<'a, Brand: Compactable, A: 'a>(
198 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
199 'a,
200 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
201 >)
202 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
203 Brand::compact(fa)
204 }
205
206 /// Separates a data structure of [`Result`]s into two data structures: one containing the [`Err`] values and one containing the [`Ok`] values.
207 ///
208 /// Free function version that dispatches to [the type class' associated function][`Compactable::separate`].
209 #[document_signature]
210 ///
211 #[document_type_parameters(
212 "The lifetime of the elements.",
213 "The brand of the compactable structure.",
214 "The type of the error values.",
215 "The type of the success values."
216 )]
217 ///
218 #[document_parameters("The data structure containing [`Result`] values.")]
219 ///
220 #[document_returns(
221 "A pair of data structures: the first containing the [`Err`] values, and the second containing the [`Ok`] values."
222 )]
223 #[document_examples]
224 ///
225 /// ```
226 /// use fp_library::{
227 /// brands::*,
228 /// functions::*,
229 /// };
230 ///
231 /// let x: Option<Result<i32, &str>> = Some(Ok(5));
232 /// let (errs, oks) = separate::<OptionBrand, _, _>(x);
233 /// assert_eq!(oks, Some(5));
234 /// assert_eq!(errs, None);
235 /// ```
236 pub fn separate<'a, Brand: Compactable, E: 'a, O: 'a>(
237 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
238 ) -> (
239 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
240 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
241 ) {
242 Brand::separate::<E, O>(fa)
243 }
244}
245
246pub use inner::*;