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::{brands::*, functions::*};
7//!
8//! let x = Some(Some(5));
9//! let y = compact::<OptionBrand, _>(x);
10//! assert_eq!(y, Some(5));
11//! ```
12
13use crate::{Apply, brands::OptionBrand, kinds::*, types::Pair};
14use fp_macros::doc_params;
15use fp_macros::doc_type_params;
16use fp_macros::hm_signature;
17
18/// A type class for data structures that can be compacted and separated.
19///
20/// `Compactable` allows for:
21/// * `compact`: Filtering out [`None`] values and unwrapping [`Some`] values from a structure of [`Option`]s.
22/// * `separate`: Splitting a structure of [`Result`]s into a pair of structures, one containing the [`Err`] values and the other containing the [`Ok`] values.
23pub trait Compactable: Kind_cdc7cd43dac7585f {
24 /// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
25 ///
26 /// ### Type Signature
27 ///
28 #[hm_signature(Compactable)]
29 ///
30 /// ### Type Parameters
31 ///
32 #[doc_type_params(
33 "The lifetime of the elements.",
34 "The type of the elements in the [`Option`]."
35 )]
36 ///
37 /// ### Parameters
38 ///
39 #[doc_params("The data structure containing [`Option`] values.")]
40 ///
41 /// ### Returns
42 ///
43 /// A new data structure containing only the values from the [`Some`] variants.
44 ///
45 /// ### Examples
46 ///
47 /// ```
48 /// use fp_library::{brands::*, functions::*};
49 ///
50 /// let x = Some(Some(5));
51 /// let y = compact::<OptionBrand, _>(x);
52 /// assert_eq!(y, Some(5));
53 ///
54 /// let z = Some(None::<i32>);
55 /// let w = compact::<OptionBrand, _>(z);
56 /// assert_eq!(w, None);
57 /// ```
58 fn compact<'a, A: 'a>(
59 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
60 'a,
61 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
62 >)
63 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
64
65 /// Separates a data structure of [`Result`]s into two data structures: one containing the [`Ok`] values and one containing the [`Err`] values.
66 ///
67 /// ### Type Signature
68 ///
69 #[hm_signature(Compactable)]
70 ///
71 /// ### Type Parameters
72 ///
73 #[doc_type_params(
74 "The lifetime of the elements.",
75 "The type of the success values.",
76 "The type of the error values."
77 )]
78 ///
79 /// ### Parameters
80 ///
81 #[doc_params("The data structure containing [`Result`] values.")]
82 ///
83 /// ### Returns
84 ///
85 /// A pair of data structures: the first containing the [`Ok`] values, and the second containing the [`Err`] values.
86 ///
87 /// ### Examples
88 ///
89 /// ```
90 /// use fp_library::{brands::*, functions::*, types::*};
91 ///
92 /// let x: Option<Result<i32, &str>> = Some(Ok(5));
93 /// let Pair(oks, errs) = separate::<OptionBrand, _, _>(x);
94 /// assert_eq!(oks, Some(5));
95 /// assert_eq!(errs, None);
96 ///
97 /// let y: Option<Result<i32, &str>> = Some(Err("error"));
98 /// let Pair(oks2, errs2) = separate::<OptionBrand, _, _>(y);
99 /// assert_eq!(oks2, None);
100 /// assert_eq!(errs2, Some("error"));
101 /// ```
102 fn separate<'a, O: 'a, E: 'a>(
103 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
104 ) -> Pair<
105 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
106 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
107 >;
108}
109
110/// Compacts a data structure of [`Option`]s, discarding [`None`] values and keeping [`Some`] values.
111///
112/// Free function version that dispatches to [the type class' associated function][`Compactable::compact`].
113///
114/// ### Type Signature
115///
116#[hm_signature(Compactable)]
117///
118/// ### Type Parameters
119///
120#[doc_type_params(
121 "The lifetime of the elements.",
122 "The brand of the compactable structure.",
123 "The type of the elements in the [`Option`]."
124)]
125///
126/// ### Parameters
127///
128#[doc_params("The data structure containing [`Option`] values.")]
129///
130/// ### Returns
131///
132/// A new data structure containing only the values from the [`Some`] variants.
133///
134/// ### Examples
135///
136/// ```
137/// use fp_library::{brands::*, functions::*};
138///
139/// let x = Some(Some(5));
140/// let y = compact::<OptionBrand, _>(x);
141/// assert_eq!(y, Some(5));
142/// ```
143pub fn compact<'a, Brand: Compactable, A: 'a>(
144 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<
145 'a,
146 Apply!(<OptionBrand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
147 >)
148) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
149 Brand::compact(fa)
150}
151
152/// Separates a data structure of [`Result`]s into two data structures: one containing the [`Ok`] values and one containing the [`Err`] values.
153///
154/// Free function version that dispatches to [the type class' associated function][`Compactable::separate`].
155///
156/// ### Type Signature
157///
158#[hm_signature(Compactable)]
159///
160/// ### Type Parameters
161///
162#[doc_type_params(
163 "The lifetime of the elements.",
164 "The brand of the compactable structure.",
165 "The type of the success values.",
166 "The type of the error values."
167)]
168///
169/// ### Parameters
170///
171#[doc_params("The data structure containing [`Result`] values.")]
172///
173/// ### Returns
174///
175/// A pair of data structures: the first containing the [`Ok`] values, and the second containing the [`Err`] values.
176///
177/// ### Examples
178///
179/// ```
180/// use fp_library::{brands::*, functions::*, types::*};
181///
182/// let x: Option<Result<i32, &str>> = Some(Ok(5));
183/// let Pair(oks, errs) = separate::<OptionBrand, _, _>(x);
184/// assert_eq!(oks, Some(5));
185/// assert_eq!(errs, None);
186/// ```
187pub fn separate<'a, Brand: Compactable, O: 'a, E: 'a>(
188 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Result<O, E>>)
189) -> Pair<
190 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, O>),
191 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, E>),
192> {
193 Brand::separate::<O, E>(fa)
194}