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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
//! Sequencing of computations where the structure depends on previous results, without an identity element.
//!
//! `Semimonad` is the dual of [`Extend`](crate::classes::Extend): where `extend` feeds an
//! entire context into a function, `bind` extracts a value and feeds it into a function that
//! produces a new context. Similarly, [`join`] is the dual of
//! [`duplicate`](crate::functions::duplicate).
//!
//! ### Examples
//!
//! ```
//! use fp_library::{
//! brands::*,
//! functions::*,
//! };
//!
//! let x = Some(5);
//! let y = bind::<OptionBrand, _, _>(x, |i| Some(i * 2));
//! assert_eq!(y, Some(10));
//! ```
#[fp_macros::document_module]
mod inner {
use {
crate::kinds::*,
fp_macros::*,
};
/// Sequences two computations, allowing the second to depend on the value computed by the first.
///
/// If `x` has type `m a` and `f` has type `a -> m b`, then `bind(x, f)` has type `m b`,
/// representing the result of executing `x` to get a value of type `a` and then
/// passing it to `f` to get a computation of type `m b`.
#[kind(type Of<'a, A: 'a>: 'a;)]
pub trait Semimonad {
/// Sequences two computations, allowing the second to depend on the value computed by the first.
///
/// This method chains two computations, where the second computation depends on the result of the first.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computations.",
"The type of the result of the first computation.",
"The type of the result of the second computation."
)]
///
#[document_parameters(
"The first computation.",
"The function to apply to the result of the first computation."
)]
///
#[document_returns("The result of the second computation.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let x = Some(5);
/// let y = bind::<OptionBrand, _, _>(x, |i| Some(i * 2));
/// assert_eq!(y, Some(10));
/// ```
fn bind<'a, A: 'a, B: 'a>(
ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
func: impl Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
}
/// Sequences two computations, allowing the second to depend on the value computed by the first.
///
/// Free function version that dispatches to [the type class' associated function][`Semimonad::bind`].
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computations.",
"The brand of the semimonad.",
"The type of the result of the first computation.",
"The type of the result of the second computation."
)]
///
#[document_parameters(
"The first computation.",
"The function to apply to the result of the first computation."
)]
///
#[document_returns("The result of the second computation.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let x = Some(5);
/// let y = bind::<OptionBrand, _, _>(x, |i| Some(i * 2));
/// assert_eq!(y, Some(10));
/// ```
pub fn bind<'a, Brand: Semimonad, A: 'a, B: 'a>(
ma: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
f: impl Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
Brand::bind(ma, f)
}
/// Sequences two computations with flipped arguments, allowing the function to be provided first.
///
/// This is [`bind`] with its arguments reversed. Useful for pipelines where the function
/// is known before the computation it should be applied to.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computations.",
"The brand of the semimonad.",
"The type of the result of the first computation.",
"The type of the result of the second computation."
)]
///
#[document_parameters(
"The function to apply to the result of the computation.",
"The computation."
)]
///
#[document_returns("The result of the second computation.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let f = |i: i32| Some(i * 2);
/// let x = Some(5);
/// let y = bind_flipped::<OptionBrand, _, _>(f, x);
/// assert_eq!(y, Some(10));
/// ```
pub fn bind_flipped<'a, Brand: Semimonad, A: 'a, B: 'a>(
f: impl Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
ma: 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, B>) {
Brand::bind(ma, f)
}
/// Collapses two nested layers of a semimonad into one.
///
/// Equivalent to `bind(mma, identity)`. Removes one level of monadic wrapping
/// from a doubly-wrapped value.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computation.",
"The brand of the semimonad.",
"The type of the value inside the nested semimonad."
)]
///
#[document_parameters("The doubly-wrapped semimonadic value.")]
///
#[document_returns("The singly-wrapped semimonadic value.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let x = Some(Some(5));
/// let y = join::<OptionBrand, _>(x);
/// assert_eq!(y, Some(5));
///
/// let z: Option<Option<i32>> = Some(None);
/// assert_eq!(join::<OptionBrand, _>(z), None);
/// ```
pub fn join<'a, Brand: Semimonad, A: 'a>(
mma: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, 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::bind(mma, |ma| ma)
}
/// Forwards Kleisli composition.
///
/// Composes two monadic functions left-to-right: first applies `f`, then passes the
/// result to `g` via [`bind`]. Equivalent to Haskell's `>=>` operator.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computations.",
"The brand of the semimonad.",
"The input type of the first function.",
"The output type of the first function and input type of the second.",
"The output type of the second function."
)]
///
#[document_parameters(
"The first monadic function.",
"The second monadic function.",
"The input value."
)]
///
#[document_returns(
"The result of composing both monadic functions and applying them to the input."
)]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let parse = |s: &str| s.parse::<i32>().ok();
/// let double = |n: i32| Some(n * 2);
/// let parse_and_double = |s| compose_kleisli::<OptionBrand, _, _, _>(parse, double, s);
///
/// assert_eq!(parse_and_double("5"), Some(10));
/// assert_eq!(parse_and_double("abc"), None);
/// ```
pub fn compose_kleisli<'a, Brand: Semimonad, A: 'a, B: 'a, C: 'a>(
f: impl Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
g: impl Fn(B) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
a: A,
) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
Brand::bind(f(a), g)
}
/// Backwards Kleisli composition.
///
/// Composes two monadic functions right-to-left: first applies `g`, then passes the
/// result to `f` via [`bind`]. Equivalent to Haskell's `<=<` operator.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the computations.",
"The brand of the semimonad.",
"The input type of the second function.",
"The output type of the second function and input type of the first.",
"The output type of the first function."
)]
///
#[document_parameters(
"The second monadic function (applied after `g`).",
"The first monadic function (applied first to the input).",
"The input value."
)]
///
#[document_returns(
"The result of composing both monadic functions and applying them to the input."
)]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// functions::*,
/// };
///
/// let parse = |s: &str| s.parse::<i32>().ok();
/// let double = |n: i32| Some(n * 2);
/// let double_then_parse = |s| compose_kleisli_flipped::<OptionBrand, _, _, _>(double, parse, s);
///
/// assert_eq!(double_then_parse("5"), Some(10));
/// assert_eq!(double_then_parse("abc"), None);
/// ```
pub fn compose_kleisli_flipped<'a, Brand: Semimonad, A: 'a, B: 'a, C: 'a>(
f: impl Fn(B) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) + 'a,
g: impl Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
a: A,
) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
Brand::bind(g(a), f)
}
}
pub use inner::*;