Skip to content

Instantly share code, notes, and snippets.

@cbarrett
Last active August 22, 2017 00:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbarrett/d63e61cab268f408cb89184950662827 to your computer and use it in GitHub Desktop.
Save cbarrett/d63e61cab268f408cb89184950662827 to your computer and use it in GitHub Desktop.
Some fun with Reducers
// 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) }
}
}
@patrickt
Copy link

😍 😍

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