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
//! Monad.
//!
//! A monad is a monoid in the category of endofunctors, what these means is that
//! there must be two operations, `pure` and `flat_map`, and these two operations
//! must satisfy three laws:
//!
//! 1. Left identity: `pure(x).flat_map(f) == f(x)`
//! 2. Right identity: `m.flat_map(pure) == m`
//! 3. Associativity: `m.flat_map(f).flat_map(g) == m.flat_map(|x| f(x).flat_map(g))`
//!
//! The first law says that if we take a value, put it in a default context with
//! `pure` and then `flat_map` it with a function, we get the same result as just
//! taking the value and applying the function to it.
//!
//! The second law says that if we have a monad, we can `flat_map` it with the
//! `pure` function and the result is our original monad.
//!
//! The third law says that `flat_map` is associative. This may not be so
//! obvious, but what it's saying is that it doesn't matter how we nest our
//! `flat_map`s, the result is the same. In other words, the following two
//! expressions are equivalent:
//!
//! ```ignore
//! m.flat_map(f).flat_map(g)
//! ```
//!
//! ```ignore
//! m.flat_map(|x| f(x).flat_map(g))
//! ```
//!
//! The first law is sometimes called the "unit law" and the second law is
//! sometimes called the "morphism law". The third law is sometimes called the
//! "associativity law".
//!
//! # Examples
//!
//! ```
//! use rust2fun::prelude::*;
//! #
//! # struct CreditCard;
//! # struct User;
//! # struct Transaction;
//!
//! fn get_user(id: u32) -> Option<User> {
//! todo!("Get a user from a storage by id if it exists")
//! }
//!
//! fn get_credit_card(user: User) -> Option<CreditCard> {
//! todo!("Get a credit card of the user if it has one")
//! }
//!
//! fn charge_credit_card(amount: u32, card: CreditCard) -> Option<Transaction> {
//! todo!("Charge a credit card if it has enough money")
//! }
//!
//! fn charge_user_card(amount: u32, user_id: u32) -> Option<Transaction> {
//! get_user(user_id)
//! .flat_map(get_credit_card)
//! .flat_map(|card| charge_credit_card(amount, card))
//! }
//!
//! // Or using the `bind!` macro:
//! fn charge_user_card_alt(amount: u32, user_id: u32) -> Option<Transaction> {
//! bind! {
//! for user in get_user(user_id);
//! for card in get_credit_card(user);
//! return charge_credit_card(amount, card);
//! }
//! }
//! ```
use crateFlatMap;
use cratePure;
/// A monad. Allows composition of dependent effectful functions.
/// See [the module level documentation](self) for more.
/// Bind macro. Allows for a more natural syntax for monadic composition.
/// It is similar to the `do` notation in Haskell or the `for` notation in Scala.
///
/// # Usage
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for x in Some(1);
/// for y in Some(2);
/// x + y
/// };
/// assert_eq!(Some(3), actual);
///
/// let actual = bind! {
/// for x in Some(1);
/// for y in None::<i32>;
/// x + y
/// };
/// assert_eq!(None, actual);
/// ```
///
/// The syntax supports pattern matching, can bind variables and contain statements.
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for (_, a) in Some((1, 2));
/// let b = 3;
/// std::println!("a = {}, b = {}", a, b);
/// a + b
/// };
///
/// assert_eq!(Some(5), actual);
/// ```
///
/// Guards can be implemented using an if statement within a bind discarding the result.
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for x in Some(1);
/// for _guard in if x > 0 { Some(()) } else { None };
/// x
/// };
///
/// assert_eq!(Some(1), actual);
/// ```
///
/// ... or using the special `if` syntax for monoids.
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for x in Some(1);
/// for _guard in Some(()), if x > 0;
/// x
/// };
///
/// assert_eq!(Some(1), actual);
/// ```
///
/// The last example can be rewritten with the return syntax as follows:
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for x in Some(1);
/// return Some(x), if x > 0;
/// };
///
/// assert_eq!(Some(1), actual);
/// ```
///
/// The return keyword is used to return the result of the last bind.
///
/// ```
/// use rust2fun::prelude::*;
///
/// let actual = bind! {
/// for x in Some(1);
/// for y in Some(2);
/// return Some(x + y);
/// };
///
/// assert_eq!(Some(3), actual);
/// ```
///
/// # Examples
///
/// ```
/// use rust2fun::prelude::*;
///
/// # type AssetId = u32;
///
/// fn get_opening_prices() -> Vec<(AssetId, i32)> {
/// vec![(1, 225), (2, 310), (3, 128), (4, 99), (5, 200), (6, 0)]
/// }
///
/// fn get_closing_prices() -> Vec<(AssetId, i32)> {
/// vec![(5, 210), (3, 130), (2, 308), (4, 100), (1, 220)]
/// }
///
/// fn get_asset_name(id: AssetId) -> Option<String> {
/// match id {
/// 1 => Some("AAPL".to_string()),
/// 2 => Some("MSFT".to_string()),
/// 3 => Some("GOOG".to_string()),
/// 4 => Some("AMZN".to_string()),
/// _ => None,
/// }
/// }
///
/// let profits = bind! {
/// for (id_open, opening_price) in get_opening_prices();
/// for (id_close, closing_price) in get_closing_prices();
/// let diff = closing_price - opening_price;
/// for name in get_asset_name(id_open).into_iter().collect::<Vec<_>>(),
/// if id_open == id_close && diff > 0;
/// (name, diff)
/// };
///
/// assert_eq!(vec![("GOOG".to_string(), 2), ("AMZN".to_string(), 1)], profits);
/// ```