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