Skip to main content

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::*;