Skip to main content

fp_library/classes/
plus.rs

1//! The identity element for [`Alt`](crate::classes::Alt), forming a monoid on type constructors.
2//!
3//! `Plus` is to type constructors as [`Monoid`](crate::classes::Monoid) is to concrete types.
4//!
5//! ### Examples
6//!
7//! ```
8//! use fp_library::{
9//! 	brands::*,
10//! 	classes::*,
11//! 	functions::*,
12//! };
13//!
14//! let x = alt::<OptionBrand, _>(plus_empty::<OptionBrand, i32>(), Some(5));
15//! assert_eq!(x, Some(5));
16//! ```
17
18#[fp_macros::document_module]
19mod inner {
20	use {
21		crate::{
22			classes::*,
23			kinds::*,
24		},
25		fp_macros::*,
26	};
27
28	/// A type class extending [`Alt`] with an identity element.
29	///
30	/// `Plus` is similar to [`Monoid`], except that it applies to types of
31	/// kind `* -> *` (like `Option` or `Vec`) rather than concrete types.
32	///
33	/// ### Laws
34	///
35	/// `Plus` instances must satisfy the following laws:
36	/// * Left identity: `alt(empty, x) = x`.
37	/// * Right identity: `alt(x, empty) = x`.
38	/// * Annihilation: `map(f, empty) = empty`.
39	#[document_examples]
40	///
41	/// Plus laws for [`Option`]:
42	///
43	/// ```
44	/// use fp_library::{
45	/// 	brands::*,
46	/// 	classes::*,
47	/// 	functions::*,
48	/// };
49	///
50	/// // Left identity: alt(empty, x) = x
51	/// let x = Some(5);
52	/// assert_eq!(alt::<OptionBrand, _>(plus_empty::<OptionBrand, i32>(), x), x,);
53	///
54	/// // Right identity: alt(x, empty) = x
55	/// assert_eq!(alt::<OptionBrand, _>(x, plus_empty::<OptionBrand, i32>()), x,);
56	///
57	/// // Annihilation: map(f, empty) = empty
58	/// let f = |i: i32| i * 2;
59	/// assert_eq!(
60	/// 	map::<OptionBrand, _, _>(f, plus_empty::<OptionBrand, i32>()),
61	/// 	plus_empty::<OptionBrand, i32>(),
62	/// );
63	/// ```
64	pub trait Plus: Alt {
65		/// Returns the identity element for [`alt`](Alt::alt).
66		///
67		/// This is the empty/failure value for the type constructor.
68		/// For `Option`, this is `None`. For `Vec`, this is `vec![]`.
69		#[document_signature]
70		///
71		#[document_type_parameters(
72			"The lifetime of the value.",
73			"The type of the value inside the context."
74		)]
75		///
76		#[document_returns("The identity element.")]
77		#[document_examples]
78		///
79		/// ```
80		/// use fp_library::{
81		/// 	brands::*,
82		/// 	functions::*,
83		/// };
84		///
85		/// let x: Option<i32> = plus_empty::<OptionBrand, i32>();
86		/// assert_eq!(x, None);
87		/// ```
88		fn empty<'a, A: 'a>() -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
89	}
90
91	/// Returns the identity element for [`alt`](crate::classes::Alt::alt).
92	///
93	/// Free function version that dispatches to [the type class' associated function][`Plus::empty`].
94	#[document_signature]
95	///
96	#[document_type_parameters(
97		"The lifetime of the value.",
98		"The brand of the context.",
99		"The type of the value inside the context."
100	)]
101	///
102	#[document_returns("The identity element.")]
103	#[document_examples]
104	///
105	/// ```
106	/// use fp_library::{
107	/// 	brands::*,
108	/// 	functions::*,
109	/// };
110	///
111	/// let x: Option<i32> = plus_empty::<OptionBrand, i32>();
112	/// assert_eq!(x, None);
113	/// ```
114	pub fn empty<'a, Brand: Plus, A: 'a>()
115	-> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
116		Brand::empty()
117	}
118}
119
120pub use inner::*;