import Cocoa enum Failable<T> { case fail case success(T) func map<U>(fn: (T) -> U) -> Failable<U> { switch self { case .fail: return .fail case let .success(t): return .success(fn(t)) } } func flatMap<U>(fn: (T) -> Failable<U>) -> Failable<U> { switch self { case .fail: return .fail case let .success(t): return fn(t) } } } func repeatedlyAttempt<T>(attempts: Int, fn: () -> Failable<T>) -> Failable<T> { guard attempts > 0 else { return .fail } let attempted = fn() switch attempted { case .success(_): return attempted case .fail: return repeatedlyAttempt(attempts: attempts - 1, fn: fn) } } func randomlyFail<T>(fn: () -> T) -> Failable<T> { return (arc4random_uniform(2) == 1) ? .success(fn()) : .fail } func doThing(i: Int) -> String { return "\(i)" } func reverseDoThing(s: String) -> Int { return Int(s)! } let failableDoThing = { i in randomlyFail(fn: { doThing(i: i) }) } let failableReverseDoThing = { s in randomlyFail(fn: { reverseDoThing(s: s) }) } repeatedlyAttempt(attempts: 5){ failableDoThing(10) } .flatMap{s in repeatedlyAttempt(attempts: 5){ failableReverseDoThing(s) } }