Created
September 20, 2016 14:02
-
-
Save anonymous/ef4e68c2ed457ab6cdc09469f10208c6 to your computer and use it in GitHub Desktop.
Result Parsing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
typealias JSONKey = String | |
typealias JSONValue = AnyObject | |
typealias JSON = [JSONKey: JSONValue] | |
public func identity<T>(value: T) -> T { | |
return value | |
} | |
enum Result<Wrapped, WrappedError> { | |
case Success(Wrapped) | |
case Error(WrappedError) | |
func map<T>(f: (Wrapped -> T)) -> Result<T, WrappedError> { | |
return mapResult(success: f, failure: identity) | |
} | |
func mapError<T>(f: (WrappedError) -> T) -> Result<Wrapped, T> { | |
return mapResult(success: identity, failure: f) | |
} | |
func apply<T>(f: Result<(Wrapped -> T), WrappedError>) -> Result<T, WrappedError> { | |
switch self { | |
case let .Success(value): return f.map { $0(value) } | |
case let .Error(error): return .Error(error) | |
} | |
} | |
func flatMap<T>(f: (Wrapped -> Result<T, WrappedError>)) -> Result<T, WrappedError> { | |
switch self { | |
case let .Success(value): return f(value) | |
case let .Error(error): return .Error(error) | |
} | |
} | |
func mapResult<RT, RE>(success success: (Wrapped) -> RT, failure: (WrappedError) -> RE) -> Result<RT, RE> { | |
switch self { | |
case let .Success(value): return .Success(success(value)) | |
case let .Error(error): return .Error(failure(error)) | |
} | |
} | |
} | |
extension Optional { | |
func reduce<A>(accumulator: A, f: (A, Wrapped) -> A) -> A { | |
switch self { | |
case let .Some(value): return f(accumulator, value) | |
case .None: return accumulator | |
} | |
} | |
func toResult<E>(error: E) -> Result<Wrapped, E> { | |
// too stupid to infer the type | |
return self.reduce(.Error(error)) { accumulator, value in | |
.Success(value) | |
} | |
} | |
} | |
func transform<T, R>(value: T) -> Result<R, String> { | |
return (value as? R).toResult("couldn't transform value = \(value) of type \(T.self) to \(R.self)") | |
} | |
func toJSON<T>(value: T) -> Result<JSON, String> { | |
return transform(value) | |
} | |
extension Dictionary { | |
func extract<T>(key: Key) -> Result<T, String> { | |
return transform(self[key]).mapError { "couldn't extract key = \(key) in \(self), " + $0 } | |
} | |
} | |
infix operator |> { associativity left } // pipe | |
func |><A, B>(value: A, f: A -> B) -> B { | |
return f(value) | |
} | |
infix operator >>- { associativity left } // flatMap | |
func >>-<T, R, E>(value: Result<T, E>, f: T -> Result<R, E>) -> Result<R, E> { | |
return value.flatMap(f) | |
} | |
infix operator <^> { associativity left } // map | |
func <^><T, R, E>(f: T -> R, value: Result<T, E>) -> Result<R, E> { | |
return value.map(f) | |
} | |
infix operator <*> { associativity left } // apply | |
func <*><T, R, E>(f: Result<(T -> R), E>, value: Result<T, E>) -> Result<R, E> { | |
return value.apply(f) | |
} | |
func curry<A, B, C, R>(f: (A, B, C) -> R) -> A -> B -> C -> R { | |
return { a in | |
{ b in | |
{ c in | |
f(a, b, c) | |
} | |
} | |
} | |
} | |
struct User { | |
let id: Int | |
let name: String | |
let email: String? | |
static let create = curry(User.init) | |
} | |
let jsonOptional: NSDictionary? = ["id" : 1, "name" : 2, "email" : "aaa@mail.com"] | |
let user = jsonOptional |> toJSON >>- { json in | |
return User.create | |
<^> json.extract("id") | |
<*> json.extract("name") | |
<*> json.extract("email") | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment