I have an array of Swift Result
, like this:
let tuple: [Result<Term, TermError>] = /* code here */
I want to turn this inside out, pulling the results out to give a single result, with the array pushed inside it.
let tuple2: Result<[Term], TermError> = /* How? */
tuple2
should be .failure
if any of tuple
are .failure
. Otherwise it is .success([tuple-elements-in-here])
.
I think I can come up with something that will make this work, but I feel like there ought to be a fairly clean way to achieve this?
You are actually just trying to recreate the sequence
function for Haskell Monads in Swift, for the Result
monad. We can implement it exactly the same way Haskell implemented it.
sequence :: Monad m => [m a] -> m [a]
sequence = foldr mcons (return [])
where mcons p q = p >>= \x -> q >>= \y -> return (x:y)
In Swift, this would look like:
func sequence<T, E: Error>(_ arrayOfResults: [Result<T, E>]) -> Result<[T], E> {
return arrayOfResults.reduce(.success([])) { (p, q) in
return p.flatMap { x in return q.map { y in return x + [y] } }
}
}
Usage:
let tuple2 = sequence(tuple)
You can define an extension
on Array
that converts an Array<Result<Value,Error>> to
Result,Error>` like below.
extension Array {
func flatMapResult<Value, Error>() -> Result<Array<Value>,Error> where Element == Result<Value,Error> {
let valuesAndErrors = self.map { element -> (value: Value?, error: Error?) in
switch element {
case .failure(let error):
return (nil, error)
case .success(let value):
return (value, nil)
}
}
if let firstElementWithError = valuesAndErrors.first(where: {$0.error != nil}), let firstError = firstElementWithError.error {
return .failure(firstError)
} else {
let values = valuesAndErrors.compactMap { $0.value }
return .success(values)
}
}
}
Code sample for usage:
enum MyError: Error {
case err
}
let arrayOfResults: Array<Result<Int,MyError>> = [.success(8), .success(2), .success(3)] // success([8, 2, 3])
let arrayOfResultsWithFailure = arrayOfResults + [.failure(.err)] // failure(__lldb_expr_2.MyError.err)
arrayOfResults.flatMapResult()
arrayOfResultsWithFailure.flatMapResult()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With