1
import Foundation
2

3
/// An ApplicativeError is an `Applicative` that has capabilities to raise and handle error values.
4
///
5
/// It has an associated type `E` to represent the error type that the implementing instance is able to handle.
6
public protocol ApplicativeError: Applicative {
7
    /// Error type associated to this `ApplicativeError` instance
8
    associatedtype E
9

10
    /// Lifts an error to the context implementing this instance.
11
    ///
12
    /// - Parameter e: A value of the error type.
13
    /// - Returns: A value representing the error in the context implementing this instance.
14
    static func raiseError<A>(_ e: E) -> Kind<Self, A>
15

16
    /// Handles an error, potentially recovering from it by mapping it to a value in the context implementing this instance.
17
    ///
18
    /// - Parameters:
19
    ///   - fa: A computation that may have an error.
20
    ///   - f: A recovery function.
21
    /// - Returns: A value where the possible errors have been recovered using the provided function.
22
    static func handleErrorWith<A>(_ fa: Kind<Self, A>, _ f: @escaping (E) -> Kind<Self, A>) -> Kind<Self, A>
23
}
24

25
// MARK: Related functions
26

27
public extension ApplicativeError {
28
    /// Handles an error, potentially recovering from it by mapping it to a value.
29
    ///
30
    /// - Parameters:
31
    ///   - fa: A computation that may have an error.
32
    ///   - f: A recovery function.
33
    /// - Returns: A value where the possible errors have been recovered using the provided function.
34 1
    static func handleError<A>(_ fa: Kind<Self, A>, _ f: @escaping (E) -> A) -> Kind<Self, A> {
35 1
        return handleErrorWith(fa, { a in self.pure(f(a)) })
36
    }
37

38
    /// Handles errors by converting them into `Either` values in the context implementing this instance.
39
    ///
40
    /// - Parameter fa: A computation that may have an error.
41
    /// - Returns: An either wrapped in the context implementing this instance.
42 1
    static func attempt<A>(_ fa: Kind<Self, A>) -> Kind<Self, Either<E, A>> {
43 1
        return handleErrorWith(map(fa, Either<E, A>.right), { e in self.pure(Either<E, A>.left(e)) })
44
    }
45

46
    /// Converts an `Either` value into a value in the context implementing this instance.
47
    ///
48
    /// - Parameter fea: An `Either` value.
49
    /// - Returns: A value in the context implementing this instance.
50 1
    static func fromEither<A>(_ fea: Either<E, A>) -> Kind<Self, A> {
51 1
        return fea.fold(raiseError, pure)
52
    }
53
    
54
    /// Converts an `Option` value into a value in the context implementing this instance.
55
    ///
56
    /// - Parameters:
57
    ///   - oa: An `Option` value.
58
    ///   - f: A function providing the error value in case the option is empty.
59
    /// - Returns: A value in the context implementing this instance.
60 0
    static func fromOption<A>(_ oa: Option<A>, _ f: () -> E) -> Kind<Self, A> {
61 0
        return oa.fold({ Self.raiseError(f()) }, Self.pure)
62
    }
63
    
64
    /// Converts a `Try` value into a value in the context implementing this instance.
65
    ///
66
    /// - Parameters:
67
    ///   - ta: A `Try` value.
68
    ///   - f: A function transforming the error contained in `Try` to the error type of this instance.
69
    /// - Returns: A value in the context implementing this instance.
70 0
    static func fromTry<A>(_ ta: Try<A>, _ f: (Error) -> E) -> Kind<Self, A> {
71 0
        return ta.fold({ e in Self.raiseError(f(e)) }, Self.pure)
72
    }
73

74
    /// Evaluates a throwing function, catching and mapping errors.
75
    ///
76
    /// - Parameters:
77
    ///   - f: A throwing function.
78
    ///   - recover: A function that maps from `Error` to the type that this instance is able to handle.
79
    /// - Returns: A value in the context implementing this instance.
80 1
    static func catchError<A>(_ f: () throws -> A, _ recover: (Error) -> E) -> Kind<Self, A> {
81 1
        do {
82 1
            return pure(try f())
83 1
        } catch {
84 1
            return raiseError(recover(error))
85
        }
86
    }
87

88
    /// Evaluates a throwing function, catching errors.
89
    ///
90
    /// - Parameter f: A throwing function.
91
    /// - Returns: A value in the context implementing this instance.
92 0
    static func catchError<A>(_ f: () throws -> A) -> Kind<Self, A> where Self.E == Error {
93 0
        do {
94 0
            return pure(try f())
95 0
        } catch {
96 0
            return raiseError(error)
97
        }
98
    }
99
}
100

101
// MARK: Syntax for ApplicativeError
102

103
public extension Kind where F: ApplicativeError {
104
    /// Lifts an error to the context implementing this instance.
105
    ///
106
    /// This is a convenience method to call `ApplicativeError.raiseError` as a static method of this type.
107
    ///
108
    /// - Parameter e: A value of the error type.
109
    /// - Returns: A value representing the error in the context implementing this instance.
110 0
    static func raiseError(_ e: F.E) -> Kind<F, A> {
111 0
        return F.raiseError(e)
112
    }
113

114
    /// Handles an error, potentially recovering from it by mapping it to a value in the context implementing this instance.
115
    ///
116
    /// This is a convenience method to call `ApplicativeError.handleErrorWith` as an instance method of this type.
117
    ///
118
    /// - Parameters:
119
    ///   - f: A recovery function.
120
    /// - Returns: A value where the possible errors have been recovered using the provided function.
121 1
    func handleErrorWith(_ f: @escaping (F.E) -> Kind<F, A>) -> Kind<F, A> {
122 1
        return F.handleErrorWith(self, f)
123
    }
124

125
    /// Handles an error, potentially recovering from it by mapping it to a value.
126
    ///
127
    /// This is a convenience method to call `ApplicativeError.handleError` as an instance method of this type.
128
    ///
129
    /// - Parameters:
130
    ///   - f: A recovery function.
131
    /// - Returns: A value where the possible errors have been recovered using the provided function.
132 0
    func handleError(_ f: @escaping (F.E) -> A) -> Kind<F, A> {
133 0
        return F.handleError(self, f)
134
    }
135

136
    /// Handles errors by converting them into `Either` values in the context implementing this instance.
137
    ///
138
    /// This is a convenience method to call `ApplicativeError.attempt` as an instance method of this type.
139
    ///
140
    /// - Returns: An either wrapped in the context implementing this instance.
141 0
    func attempt() -> Kind<F, Either<F.E, A>> {
142 0
        return F.attempt(self)
143
    }
144

145
    /// Converts an `Either` value into a value in the context implementing this instance.
146
    ///
147
    /// This is a convenience method to call `ApplicativeError.fromEither` as a static method of this type.
148
    ///
149
    /// - Parameter fea: An `Either` value.
150
    /// - Returns: A value in the context implementing this instance.
151 1
    static func fromEither(_ fea: Either<F.E, A>) -> Kind<F, A> {
152 1
        return F.fromEither(fea)
153
    }
154

155
    /// Converts an `Option` value into a value in the context implementing this instance.
156
    ///
157
    /// - Parameters:
158
    ///   - oa: An `Option` value.
159
    ///   - f: A function providing the error value in case the option is empty.
160
    /// - Returns: A value in the context implementing this instance.
161 0
    static func fromOption(_ oa: Option<A>, _ f: () -> F.E) -> Kind<F, A> {
162 0
        return F.fromOption(oa, f)
163
    }
164

165
    /// Converts a `Try` value into a value in the context implementing this instance.
166
    ///
167
    /// - Parameters:
168
    ///   - ta: A `Try` value.
169
    ///   - f: A function transforming the error contained in `Try` to the error type of this instance.
170
    /// - Returns: A value in the context implementing this instance.
171 0
    static func fromTry(_ ta: Try<A>, _ f: (Error) -> F.E) -> Kind<F, A> {
172 0
        return F.fromTry(ta, f)
173
    }
174
    
175
    /// Evaluates a throwing function, catching and mapping errors.
176
    ///
177
    /// This is a convenience method to call `ApplicativeError.catchError` as a static method of this type.
178
    ///
179
    /// - Parameters:
180
    ///   - f: A throwing function.
181
    ///   - recover: A function that maps from `Error` to the type that this instance is able to handle.
182
    /// - Returns: A value in the context implementing this instance.
183 0
    static func catchError(_ f: () throws -> A, _ recover: (Error) -> F.E) -> Kind<F, A> {
184 0
        return F.catchError(f, recover)
185
    }
186
}
187

188
public extension Kind where F: ApplicativeError, F.E == Error {
189
    /// Evaluates a throwing function, catching errors.
190
    ///
191
    /// This is a convenience method to call `ApplicativeError.catchError` as a static method of this type.
192
    ///
193
    /// - Parameter f: A throwing function.
194
    /// - Returns: A value in the context implementing this instance.
195 0
    static func catchError(_ f: () throws -> A) -> Kind<F, A> {
196 0
        return F.catchError(f)
197
    }
198
}

Read our documentation on viewing source code .

Loading