Skip to content

Instantly share code, notes, and snippets.

Created September 20, 2016 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/ef4e68c2ed457ab6cdc09469f10208c6 to your computer and use it in GitHub Desktop.
Save anonymous/ef4e68c2ed457ab6cdc09469f10208c6 to your computer and use it in GitHub Desktop.
Result Parsing
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