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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Choosing between values in a context, associatively.
//!
//! `Alt` is to type constructors as [`Semigroup`](crate::classes::Semigroup) is to concrete types.
//!
//! ### Examples
//!
//! ```
//! use fp_library::{
//! brands::*,
//! classes::*,
//! functions::explicit::*,
//! };
//!
//! let x: Option<i32> = None;
//! let y = Some(5);
//! let z = alt::<OptionBrand, _, _, _>(x, y);
//! assert_eq!(z, Some(5));
//! ```
#[fp_macros::document_module]
mod inner {
use {
crate::{
classes::*,
kinds::*,
},
fp_macros::*,
};
/// A type class for associative choice on type constructors.
///
/// `Alt` is similar to [`Semigroup`], except that it applies to types of
/// kind `* -> *` (like `Option` or `Vec`) rather than concrete types
/// (like `String` or `i32`).
///
/// A common use case is to select the first "valid" item, or, if all items
/// are "invalid", fall back to the last item.
///
/// ### Laws
///
/// `Alt` instances must satisfy the following laws:
/// * Associativity: `alt(alt(x, y), z) = alt(x, alt(y, z))`.
/// * Distributivity: `map(f, alt(x, y)) = alt(map(f, x), map(f, y))`.
#[document_examples]
///
/// Alt laws for [`Option`]:
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::*,
/// functions::explicit::*,
/// };
///
/// // Associativity: alt(alt(x, y), z) = alt(x, alt(y, z))
/// let x: Option<i32> = None;
/// let y = Some(1);
/// let z = Some(2);
/// assert_eq!(
/// alt::<OptionBrand, _, _, _>(alt::<OptionBrand, _, _, _>(x, y), z),
/// alt::<OptionBrand, _, _, _>(x, alt::<OptionBrand, _, _, _>(y, z)),
/// );
///
/// // Distributivity: map(f, alt(x, y)) = alt(map(f, x), map(f, y))
/// let f = |i: i32| i * 2;
/// let x = Some(3);
/// let y: Option<i32> = None;
/// assert_eq!(
/// map::<OptionBrand, _, _, _, _>(f, alt::<OptionBrand, _, _, _>(x, y)),
/// alt::<OptionBrand, _, _, _>(
/// map::<OptionBrand, _, _, _, _>(f, x),
/// map::<OptionBrand, _, _, _, _>(f, y)
/// ),
/// );
/// ```
pub trait Alt: Functor {
/// Chooses between two values in a context.
///
/// This method provides an associative binary operation on type constructors.
/// For `Option`, this returns the first `Some` value. For `Vec`, this
/// concatenates the two vectors.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the values.",
"The type of the value inside the context."
)]
///
#[document_parameters("The first value.", "The second value.")]
///
#[document_returns("The chosen/combined value.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::*,
/// functions::explicit::*,
/// };
///
/// let x: Option<i32> = None;
/// let y = Some(5);
/// let z = alt::<OptionBrand, _, _, _>(x, y);
/// assert_eq!(z, Some(5));
/// ```
fn alt<'a, A: 'a>(
fa1: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
fa2: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
}
/// Chooses between two values in a context.
///
/// Free function version that dispatches to [the type class' associated function][`Alt::alt`].
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the context.",
"The type of the value inside the context."
)]
///
#[document_parameters("The first value.", "The second value.")]
///
#[document_returns("The chosen/combined value.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::*,
/// functions::explicit::*,
/// };
///
/// let x: Option<i32> = None;
/// let y = Some(5);
/// let z = alt::<OptionBrand, _, _, _>(x, y);
/// assert_eq!(z, Some(5));
/// ```
pub fn alt<'a, Brand: Alt, A: 'a>(
fa1: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
fa2: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
Brand::alt(fa1, fa2)
}
}
pub use inner::*;