Last active
August 29, 2015 14:14
-
-
Save jarsen/87fb5bbe4c1ed425c084 to your computer and use it in GitHub Desktop.
Pipeline operator inspired by Elixir and http://undefinedvalue.com/2014/07/13/fs-pipe-forward-operator-swift
This file contains hidden or 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
// Playground - noun: a place where people can play | |
import UIKit | |
import CoreGraphics | |
public enum Result<T> { | |
case Success(@autoclosure () -> T) | |
case Failure(String) | |
init(_ value:T) { | |
self = .Success(value) | |
} | |
} | |
extension Result { | |
public func bind<U>(f: T -> Result<U>) -> Result<U> { | |
switch self { | |
case let .Success(value): | |
return f(value()) | |
case let .Failure(error): | |
return .Failure(error) | |
} | |
} | |
public func fmap<U>(f: T->U) -> Result<U> { | |
switch self { | |
case let .Success(value): | |
return .Success(f(value())) | |
case let .Failure(error): | |
return .Failure(error) | |
} | |
} | |
public func forceUnwrap() -> T { | |
switch self { | |
case let .Success(value): | |
return value() | |
case let .Failure: | |
assertionFailure("You force unwrapped \(self), which was not a Result.Success") | |
} | |
} | |
} | |
infix operator |> { precedence 50 associativity left } | |
// MARK: Curry | |
public func curry<A, B, Z>(f: (A, B) -> Z) -> A -> B -> Z { | |
return { a in { b in f(a, b) } } | |
} | |
public func curry<A, B, C, Z>(f: (A, B, C) -> Z) -> A -> B -> C -> Z { | |
return { a in { b in { c in f(a, b, c) } } } | |
} | |
public func curry<A, B, C, D, Z>(f: (A, B, C, D) -> Z) -> A -> B -> C -> D -> Z { | |
return { a in { b in { c in { d in f(a, b, c, d) } } } } | |
} | |
public func curry<A, B, C, D, E, Z>(f: (A, B, C, D, E) -> Z) -> A -> B -> C -> D -> E -> Z { | |
return { a in { b in { c in { d in { e in f(a, b, c, d, e) } } } } } | |
} | |
// MARK: Reverse Curry | |
public func reverseCurry<A, B, Z>(f: (A, B) -> Z) -> B -> A -> Z { | |
return { b in { a in f(a, b) } } | |
} | |
public func reverseCurry<A, B, C, Z>(f: (A, B, C) -> Z) -> C -> B -> A -> Z { | |
return {c in { b in { a in f(a, b, c) } } } | |
} | |
public func reverseCurry<A, B, C, D, Z>(f: (A, B, C, D) -> Z) -> D -> C -> B -> A -> Z { | |
return { d in { c in { b in { a in f(a, b, c, d) } } } } | |
} | |
public func reverseCurry<A, B, C, D, E, Z>(f: (A, B, C, D, E) -> Z) -> E -> D -> C -> B -> A -> Z { | |
return { e in { d in { c in { b in { a in f(a, b, c, d, e) } } } } } | |
} | |
// MARK: Pipeline | |
public func |> <A,Z>(lhs: A, rhs: A -> Z) -> Z { | |
return rhs(lhs) | |
} | |
public func |> <A,B,Z>(lhs: A, rhs: ((A, B) -> Z, B)) -> Z { | |
return rhs.0(lhs, rhs.1) | |
} | |
public func |> <A,B,C,Z>(lhs: A, rhs: (((A, B, C) -> Z), B, C)) -> Z { | |
return rhs.0(lhs, rhs.1, rhs.2) | |
} | |
// MARK: Optional Pipeline | |
public func |> <A, Z>(lhs: A?, rhs: A -> Z) -> Z? { | |
return map(lhs, rhs) | |
} | |
public func |> <A, B, Z>(lhs: A?, rhs: ((A, B) -> Z, B)) -> Z? { | |
return map(lhs, reverseCurry(rhs.0)(rhs.1)) | |
} | |
public func |> <A,B,C,Z>(lhs: A?, rhs: (((A, B, C) -> Z), B, C)) -> Z? { | |
return map(lhs, reverseCurry(rhs.0)(rhs.2)(rhs.1)) | |
} | |
// MARK: Result Pipeline | |
public func |> <A,Z>(lhs: Result<A>, rhs: A -> Z) -> Result<Z> { | |
return lhs.fmap(rhs) | |
} | |
public func |> <A,B,Z>(lhs: Result<A>, rhs: ((A, B) -> Z, B)) -> Result<Z> { | |
return lhs.fmap(reverseCurry(rhs.0)(rhs.1)) | |
} | |
public func |> <A,B,C,Z>(lhs: Result<A>, rhs: (((A, B, C) -> Z), B, C)) -> Result<Z> { | |
return lhs.fmap(reverseCurry(rhs.0)(rhs.2)(rhs.1)) | |
} | |
// MARK: Examples | |
func increment(int: Int) -> Int { | |
return int + 1 | |
} | |
2 |> increment | |
// clear, concise, and functional, but only works on arrays. | |
// does not generalize to Sequence | |
let example1 = [1,2,3,4,5].filter({$0 % 2 == 0}).map({$0 * 3}).reduce(0, +) | |
example1 | |
// this is dirtier than example1, but generalized to Sequence | |
let example2 = reduce(map(filter([1,2,3,4,5], {$0 % 2 == 0}), {$0 * 3}), 0, +) | |
example2 | |
// works on sequences and clean | |
let example3 = [1,2,3,4,5] | |
|> (filter, {$0 % 2 == 0}) | |
|> (map, {$0 * 3}) | |
|> (reduce, 0, +) | |
example3 | |
// Optional examples | |
let elements = [2, 4, 6, 8, 10] | |
let isEvenIndex = find(elements, 6) |> { $0 % 2 == 0} // "Found 6 at index 2" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment