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