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