1
|
|
import Foundation
|
2
|
|
|
3
|
|
/// A Monad provides functionality to sequence operations that are dependent from one another.
|
4
|
|
///
|
5
|
|
/// Instances of `Monad` must obey the following rules:
|
6
|
|
///
|
7
|
|
/// flatMap(pure(a), f) == f(a)
|
8
|
|
/// flatMap(fa, pure) == fa
|
9
|
|
/// flatMap(fa) { a in flatMap(f(a), g) } == flatMap(flatMap(fa, f), g)
|
10
|
|
///
|
11
|
|
/// Also, instances of `Monad` derive a default implementation for `Applicative.ap` as:
|
12
|
|
///
|
13
|
|
/// ap(ff, fa) == flapMap(ff, { f in map(fa, f) }
|
14
|
|
public protocol Monad: Selective {
|
15
|
|
/// Sequentially compose two computations, passing any value produced by the first as an argument to the second.
|
16
|
|
///
|
17
|
|
/// - Parameters:
|
18
|
|
/// - fa: First computation.
|
19
|
|
/// - f: A function describing the second computation, which depends on the value of the first.
|
20
|
|
/// - Returns: Result of composing the two computations.
|
21
|
|
static func flatMap<A, B>(_ fa: Kind<Self, A>, _ f: @escaping (A) -> Kind<Self, B>) -> Kind<Self, B>
|
22
|
|
|
23
|
|
/// Monadic tail recursion.
|
24
|
|
///
|
25
|
|
/// `tailRecM` can be used for computations that can potentially make the stack overflow.
|
26
|
|
///
|
27
|
|
/// Initially introduced in [Stack Safety for Free](https://functorial.com/stack-safety-for-free/index.pdf)
|
28
|
|
///
|
29
|
|
/// - Parameters:
|
30
|
|
/// - a: Initial value for the recursion.
|
31
|
|
/// - f: A function describing a recursive step.
|
32
|
|
/// - Returns: Result of evaluating recursively the provided function with the initial value.
|
33
|
|
static func tailRecM<A, B>(_ a: A, _ f : @escaping (A) -> Kind<Self, Either<A, B>>) -> Kind<Self, B>
|
34
|
|
}
|
35
|
|
|
36
|
|
// MARK: Related functions
|
37
|
|
|
38
|
|
public extension Monad {
|
39
|
|
// Docs inherited from `Applicative`
|
40
|
1
|
static func ap<A, B>(_ ff: Kind<Self, (A) -> B>, _ fa: Kind<Self, A>) -> Kind<Self, B> {
|
41
|
1
|
return self.flatMap(ff, { f in map(fa, f) })
|
42
|
|
}
|
43
|
|
|
44
|
|
// Docs inherited from `Selective`
|
45
|
1
|
static func select<A, B>(_ fab: Kind<Self, Either<A, B>>, _ f: Kind<Self, (A) -> B>) -> Kind<Self, B> {
|
46
|
1
|
return flatMap(fab) { eab in eab.fold({ a in map(f, { ff in ff(a) }) },
|
47
|
1
|
{ b in pure(b) })}
|
48
|
|
}
|
49
|
|
|
50
|
|
/// Flattens a nested structure of the context implementing this instance into a single layer.
|
51
|
|
///
|
52
|
|
/// - Parameter ffa: Value with a nested structure.
|
53
|
|
/// - Returns: Value with a single context structure.
|
54
|
1
|
static func flatten<A>(_ ffa: Kind<Self, Kind<Self, A>>) -> Kind<Self, A> {
|
55
|
1
|
return self.flatMap(ffa, id)
|
56
|
|
}
|
57
|
|
|
58
|
|
/// Sequentially compose two computations, discarding the value produced by the first.
|
59
|
|
///
|
60
|
|
/// - Parameters:
|
61
|
|
/// - fa: 1st computation.
|
62
|
|
/// - fb: 2nd computation.
|
63
|
|
/// - Returns: Result of running the second computation after the first one.
|
64
|
0
|
static func followedBy<A, B>(_ fa: Kind<Self, A>, _ fb: Kind<Self, B>) -> Kind<Self, B> {
|
65
|
0
|
return self.flatMap(fa, { _ in fb })
|
66
|
|
}
|
67
|
|
|
68
|
|
/// Sequentially compose a computation with a potentially lazy one, discarding the value produced by the first.
|
69
|
|
///
|
70
|
|
/// - Parameters:
|
71
|
|
/// - fa: Regular computation.
|
72
|
|
/// - fb: Potentially lazy computation.
|
73
|
|
/// - Returns: Result of running the second computation after the first one.
|
74
|
0
|
static func followedByEval<A, B>(_ fa: Kind<Self, A>, _ fb: Eval<Kind<Self, B>>) -> Kind<Self, B> {
|
75
|
0
|
return self.flatMap(fa, { _ in fb.value() })
|
76
|
|
}
|
77
|
|
|
78
|
|
/// Sequentially compose two computations, discarding the value produced by the second.
|
79
|
|
///
|
80
|
|
/// - Parameters:
|
81
|
|
/// - fa: 1st computation.
|
82
|
|
/// - fb: 2nd computation.
|
83
|
|
/// - Returns: Result produced from the first computation after both are computed.
|
84
|
0
|
static func forEffect<A, B>(_ fa: Kind<Self, A>, _ fb: Kind<Self, B>) -> Kind<Self, A> {
|
85
|
0
|
return self.flatMap(fa, { a in self.map(fb, { _ in a })})
|
86
|
|
}
|
87
|
|
|
88
|
|
/// Sequentially compose a computation with a potentially lazy one, discarding the value produced by the second.
|
89
|
|
///
|
90
|
|
/// - Parameters:
|
91
|
|
/// - fa: Regular computation.
|
92
|
|
/// - fb: Potentially lazy computation.
|
93
|
|
/// - Returns: Result produced from the first computation after both are computed.
|
94
|
0
|
static func forEffectEval<A, B>(_ fa: Kind<Self, A>, _ fb: Eval<Kind<Self, B>>) -> Kind<Self, A> {
|
95
|
0
|
return self.flatMap(fa, { a in self.map(fb.value(), constant(a)) })
|
96
|
|
}
|
97
|
|
|
98
|
|
/// Pair the result of a computation with the result of applying a function to such result.
|
99
|
|
///
|
100
|
|
/// - Parameters:
|
101
|
|
/// - fa: A computation in the context implementing this instance.
|
102
|
|
/// - f: A function to be applied to the result of the computation.
|
103
|
|
/// - Returns: A tuple of the result of the computation paired with the result of the function, in the context implementing this instance.
|
104
|
0
|
static func mproduct<A, B>(_ fa: Kind<Self, A>, _ f: @escaping (A) -> Kind<Self, B>) -> Kind<Self, (A, B)> {
|
105
|
0
|
return self.flatMap(fa, { a in self.map(f(a), { b in (a, b) }) })
|
106
|
|
}
|
107
|
|
|
108
|
|
/// Conditionally apply a closure based on the boolean result of a computation.
|
109
|
|
///
|
110
|
|
/// - Parameters:
|
111
|
|
/// - fa: A boolean computation.
|
112
|
|
/// - ifTrue: Closure to be applied if the computation evaluates to `true`.
|
113
|
|
/// - ifFalse: Closure to be applied if the computation evaluates to `false`.
|
114
|
|
/// - Returns: Result of applying the corresponding closure based on the result of the computation.
|
115
|
0
|
static func ifM<B>(_ fa: Kind<Self, Bool>, _ ifTrue: @escaping () -> Kind<Self, B>, _ ifFalse: @escaping () -> Kind<Self, B>) -> Kind<Self, B> {
|
116
|
0
|
return flatMap(fa, { a in a ? ifTrue() : ifFalse() })
|
117
|
|
}
|
118
|
|
}
|
119
|
|
|
120
|
|
// MARK: Syntax for Monad
|
121
|
|
|
122
|
|
public extension Kind where F: Monad {
|
123
|
|
/// Sequentially compose this computation with another one, passing any value produced by the first as an argument to the second.
|
124
|
|
///
|
125
|
|
/// This is a convenience method to call `Monad.flatMap` as an instance method of this type.
|
126
|
|
///
|
127
|
|
/// - Parameters:
|
128
|
|
/// - f: A function describing the second computation, which depends on the value of the first.
|
129
|
|
/// - Returns: Result of composing the two computations.
|
130
|
1
|
func flatMap<B>(_ f: @escaping (A) -> Kind<F, B>) -> Kind<F, B> {
|
131
|
1
|
return F.flatMap(self, f)
|
132
|
|
}
|
133
|
|
|
134
|
|
/// Monadic tail recursion.
|
135
|
|
///
|
136
|
|
/// This is a convenience method to call `Monad.tailRecM` as a static method of this type.
|
137
|
|
///
|
138
|
|
/// - Parameters:
|
139
|
|
/// - a: Initial value for the recursion.
|
140
|
|
/// - f: A function describing a recursive step.
|
141
|
|
/// - Returns: Result of evaluating recursively the provided function with the initial value.
|
142
|
0
|
static func tailRecM<B>(_ a: A, _ f: @escaping (A) -> Kind<F, Either<A, B>>) -> Kind<F, B> {
|
143
|
0
|
return F.tailRecM(a, f)
|
144
|
|
}
|
145
|
|
|
146
|
|
/// Flattens a nested structure of the context implementing this instance into a single layer.
|
147
|
|
///
|
148
|
|
/// This is a convenience method to call `Monad.flatten` as a static method of this type.
|
149
|
|
///
|
150
|
|
/// - Parameter ffa: Value with a nested structure.
|
151
|
|
/// - Returns: Value with a single context structure.
|
152
|
0
|
static func flatten(_ ffa: Kind<F, Kind<F, A>>) -> Kind<F, A> {
|
153
|
0
|
return F.flatten(ffa)
|
154
|
|
}
|
155
|
|
|
156
|
|
/// Sequentially compose with another computation, discarding the value produced by the this one.
|
157
|
|
///
|
158
|
|
/// This is a convenience method to call `Monad.followedBy` as an instance method of this type.
|
159
|
|
///
|
160
|
|
/// - Parameters:
|
161
|
|
/// - fb: A computation.
|
162
|
|
/// - Returns: Result of running the second computation after the first one.
|
163
|
0
|
func followedBy<B>(_ fb: Kind<F, B>) -> Kind<F, B> {
|
164
|
0
|
return F.followedBy(self, fb)
|
165
|
|
}
|
166
|
|
|
167
|
|
/// Sequentially compose this computation with a potentially lazy one, discarding the value produced by this one.
|
168
|
|
///
|
169
|
|
/// This is a convenience method to call `Monad.followedByEval` as an instance method of this type.
|
170
|
|
///
|
171
|
|
/// - Parameters:
|
172
|
|
/// - fb: Lazy computation.
|
173
|
|
/// - Returns: Result of running the second computation after the first one.
|
174
|
0
|
func followedByEval<B>(_ fb: Eval<Kind<F, B>>) -> Kind<F, B> {
|
175
|
0
|
return F.followedByEval(self, fb)
|
176
|
|
}
|
177
|
|
|
178
|
|
/// Sequentially compose with another computation, discarding the value produced by the received one.
|
179
|
|
///
|
180
|
|
/// This is a convenience method to call `Monad.forEffect` as an instance method of this type.
|
181
|
|
///
|
182
|
|
/// - Parameters:
|
183
|
|
/// - fb: A computation.
|
184
|
|
/// - Returns: Result produced from the first computation after both are computed.
|
185
|
0
|
func forEffect<B>(_ fb: Kind<F, B>) -> Kind<F, A> {
|
186
|
0
|
return F.forEffect(self, fb)
|
187
|
|
}
|
188
|
|
|
189
|
|
/// Sequentially compose with a potentially lazy computation, discarding the value produced by the received one.
|
190
|
|
///
|
191
|
|
/// This is a convenience method to call `Monad.forEffectEval` as an instance method of this type.
|
192
|
|
///
|
193
|
|
/// - Parameters:
|
194
|
|
/// - fb: Lazy computation.
|
195
|
|
/// - Returns: Result produced from the first computation after both are computed.
|
196
|
0
|
func forEffectEval<B>(_ fb: Eval<Kind<F, B>>) -> Kind<F, A> {
|
197
|
0
|
return F.forEffectEval(self, fb)
|
198
|
|
}
|
199
|
|
|
200
|
|
/// Pair the result of this computation with the result of applying a function to such result.
|
201
|
|
///
|
202
|
|
/// This is a convenience method to call `Monad.mproduct` as an instance method.
|
203
|
|
///
|
204
|
|
/// - Parameters:
|
205
|
|
/// - f: A function to be applied to the result of the computation.
|
206
|
|
/// - Returns: A tuple of the result of this computation paired with the result of the function, in the context implementing this instance.
|
207
|
0
|
func mproduct<B>(_ f: @escaping (A) -> Kind<F, B>) -> Kind<F, (A, B)> {
|
208
|
0
|
return F.mproduct(self, f)
|
209
|
|
}
|
210
|
|
}
|
211
|
|
|
212
|
|
// MARK: Related functions
|
213
|
|
|
214
|
|
public extension Kind where F: Monad, A == Bool {
|
215
|
|
/// Conditionally apply a closure based on the boolean result of this computation.
|
216
|
|
///
|
217
|
|
/// This is a convenience method to call `Monad.ifM` as an instance method.
|
218
|
|
///
|
219
|
|
/// - Parameters:
|
220
|
|
/// - ifTrue: Closure to be applied if the computation evaluates to `true`.
|
221
|
|
/// - ifFalse: Closure to be applied if the computation evaluates to `false`.
|
222
|
|
/// - Returns: Result of applying the corresponding closure based on the result of the computation.
|
223
|
0
|
func ifM<B>(_ ifTrue: @escaping () -> Kind<F, B>, _ ifFalse: @escaping () -> Kind<F, B>) -> Kind<F, B> {
|
224
|
0
|
return F.ifM(self, ifTrue, ifFalse)
|
225
|
|
}
|
226
|
|
}
|