Last active
August 22, 2017 00:19
-
-
Save cbarrett/d63e61cab268f408cb89184950662827 to your computer and use it in GitHub Desktop.
Some fun with Reducers
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
// type State = ... | |
// infix operator <>: AdditionPrecedence | |
// enum Either<A, B> { ... | |
struct Reducer<Action> { | |
let reduce: (Action, State) -> State | |
init(_ f: @escaping (Action, State) -> State) { | |
reduce = f | |
} | |
} | |
extension Reducer { | |
// Reducers are monoids | |
static func <>(_ lhs: Reducer, _ rhs: Reducer) -> Reducer { | |
return Reducer() { (action, state) in | |
rhs.reduce(action, lhs.reduce(action, state)) | |
} | |
} | |
static var pass: Reducer { | |
return Reducer() { $1 } | |
} | |
// They are contravariant functors | |
func contramap<Bction>(_ f: @escaping (Bction) -> Action) -> Reducer<Bction> { | |
return Reducer<Bction>() { (b, state) in | |
return self.reduce(f(b), state) | |
} | |
} | |
// This is Kmett's Divisible, the contravariant dual of Applicative | |
static func divide<B, C>(_ f: @escaping (Action) -> (B, C)) -> (Reducer<B>, Reducer<C>) -> Reducer { | |
return { (rb, rc) in | |
return Reducer() { (action, state) in | |
let (b, c) = f(action) | |
return rc.reduce(c, rb.reduce(b, state)) | |
} | |
} | |
} | |
static func divide<B, C, D>(_ f: @escaping (Action) -> (B, C, D)) -> (Reducer<B>, Reducer<C>, Reducer<D>) -> Reducer { | |
return { (rb, rc, rd) in | |
return Reducer() { (action, state) in | |
let (b, c, d) = f(action) | |
return rd.reduce(d, rc.reduce(c, rb.reduce(b, state))) | |
} | |
} | |
} | |
// Swift has side effects, so we bring back part of the defition that Kmett elided | |
static func conquer(_ f: @escaping (Action) -> Void) -> Reducer { | |
return Reducer() { (action, _) in f(action) } | |
} | |
// This is Kmett's Decidable, the contravariant version of Alternative | |
static func choose<B, C>(_ f: @escaping (Action) -> Either<B, C>) -> (<Reducer<B>, Reducer<C>) -> Reducer { | |
return { (rb, rc) in | |
return Reducer() { (action, state) in | |
switch f(action) { | |
case let .left(b): | |
return rb.reduce(b, state) | |
case let .right(c): | |
return rc.reduce(c, state) | |
} | |
} | |
} | |
} | |
static func lose(_ f: @escaping (Action) -> Never) -> Reducer { | |
return Reducer() { (action, _) in f(action) } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
😍 😍