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
}

Read our documentation on viewing source code .

Loading