Skip to content

Instantly share code, notes, and snippets.

@philsquared
Created January 29, 2015 13:43
Show Gist options
  • Save philsquared/1d267d823130eaf7641a to your computer and use it in GitHub Desktop.
Save philsquared/1d267d823130eaf7641a to your computer and use it in GitHub Desktop.
A stab at a Result Monad (special case of Either monad) in Swift. Note that the Box helper is needed to workaround a compiler bug. Unfortunately this leaks into the usage quite considerably.
class Box<T> {
let unbox: T
init(_ value: T) { self.unbox = value }
}
enum Result<T> {
case Ok(Box<T>)
case Fail(String)
init( ok value : T ) { self = .Ok( Box( value ) ) }
init( fail msg : String ) { self = .Fail( msg ) }
var isOk: Bool {
switch self {
case .Ok: return true
case .Fail: return false
}
}
}
postfix operator >! {}
postfix func >! <T>( value: Result<T> ) -> T {
switch value {
case .Ok( let boxedValue ): return boxedValue.unbox
case .Fail( let msg ): fatalError( msg )
}
}
infix operator >>= { precedence 50 associativity left }
func >>= <T, U>( prevResult : Result<T>, nextFun : (T) -> Result<U> ) -> Result<U> {
switch prevResult {
case .Ok( let boxedValue ): return nextFun( boxedValue.unbox )
case .Fail( let msg ): return .Fail(msg)
}
}
@philsquared
Copy link
Author

Use the >! operator like ! for Optionals to force unwrap the result (which throws a fatal error if it is not ok).
Use the >>= operator as a monadic bind to sequence blocks of code that deal with Result types (it adapts the result type of one call to the result type of the next, so the final type is what you get back - or an error).

Errors just have a string message. This could be an NSError, as others have done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment