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(_ fa: Kind, _ f: @escaping (A) -> Kind) -> Kind ``` 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: A, _ f : @escaping (A) -> Kind>) -> Kind ``` 34 ```} ``` 35 36 ```// MARK: Related functions ``` 37 38 ```public extension Monad { ``` 39 ``` // Docs inherited from `Applicative` ``` 40 1 ``` static func ap(_ ff: Kind B>, _ fa: Kind) -> Kind { ``` 41 1 ``` return self.flatMap(ff, { f in map(fa, f) }) ``` 42 ``` } ``` 43 44 ``` // Docs inherited from `Selective` ``` 45 1 ``` static func select(_ fab: Kind>, _ f: Kind B>) -> Kind { ``` 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(_ ffa: Kind>) -> Kind { ``` 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(_ fa: Kind, _ fb: Kind) -> Kind { ``` 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(_ fa: Kind, _ fb: Eval>) -> Kind { ``` 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(_ fa: Kind, _ fb: Kind) -> Kind { ``` 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(_ fa: Kind, _ fb: Eval>) -> Kind { ``` 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(_ fa: Kind, _ f: @escaping (A) -> Kind) -> Kind { ``` 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(_ fa: Kind, _ ifTrue: @escaping () -> Kind, _ ifFalse: @escaping () -> Kind) -> Kind { ``` 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(_ f: @escaping (A) -> Kind) -> Kind { ``` 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(_ a: A, _ f: @escaping (A) -> Kind>) -> Kind { ``` 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>) -> Kind { ``` 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(_ fb: Kind) -> Kind { ``` 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(_ fb: Eval>) -> Kind { ``` 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(_ fb: Kind) -> Kind { ``` 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(_ fb: Eval>) -> Kind { ``` 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(_ f: @escaping (A) -> Kind) -> Kind { ``` 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(_ ifTrue: @escaping () -> Kind, _ ifFalse: @escaping () -> Kind) -> Kind { ``` 224 0 ``` return F.ifM(self, ifTrue, ifFalse) ``` 225 ``` } ``` 226 ```} ```

Read our documentation on viewing source code .