Skip to content

Instantly share code, notes, and snippets.

@rjchatfield
Created August 22, 2015 16:59
Show Gist options
  • Save rjchatfield/27e3d8ef2249a4298046 to your computer and use it in GitHub Desktop.
Save rjchatfield/27e3d8ef2249a4298046 to your computer and use it in GitHub Desktop.
Inspired by Redux, but not really Redux
// ACTIONS & REDUCERS
enum CounterAction {
case Increment
case Decrement
case ChangeBy(Int)
}
enum NameAction {
case Set(String)
case Clear
}
func counter(state: Int?, action: CounterAction) -> Int? {
let _state = state ?? 0
switch action {
case .Increment: return _state.successor()
case .Decrement: return _state.predecessor()
case .ChangeBy(let x): return _state + x
}
}
func namer(_: String?, action: NameAction) -> String? {
switch action {
case .Clear: return nil
case .Set(let name): return name
}
}
// Imperative
let a = counter(nil, action: .Increment)
let b = counter(a, action: .Increment)
let c = counter(b, action: .ChangeBy(100))
let d = counter(c, action: .Decrement)
let w = namer(nil, action: .Set("John"))
let x = namer(w, action: .Clear)
let y = namer(x, action: .Set("Rob"))
// Chain with structs
struct Counter {
let value: Int?
func set(action: CounterAction) -> Counter {
return Counter(value: counter(value, action: action))
}
}
struct Namer {
let value: String?
func set(action: NameAction) -> Namer {
return Namer(value: namer(value, action: action))
}
}
let e = Counter(value: 0)
.set(.Increment)
.set(.Increment)
.set(.ChangeBy(100))
.set(.Decrement)
.value
let z = Namer(value: "")
.set(.Set("John"))
.set(.Clear)
.set(.Set("Rob"))
.value
// Combine with reduce()
let acts1: [CounterAction] = [.Increment, .Increment, .ChangeBy(100), .Decrement]
acts1.reduce(0) { counter($0, action: $1) }
let acts2: [NameAction] = [.Set("John"), .Clear, .Set("Rob")]
acts2.reduce("") { namer($0, action: $1) }
// Combine many states using combined reducers
enum ActionKey {
case Counter
case Name
}
protocol ActionType {
var key: ActionKey { get }
}
extension CounterAction: ActionType {
var key: ActionKey { return .Counter }
}
extension NameAction: ActionType {
var key: ActionKey { return .Name }
}
typealias StateValueType = [ActionKey: Any?]
struct State {
let value: StateValueType
init(value: StateValueType) { self.value = value }
init() { value = [:] }
func merge(newState: StateValueType) -> State {
var _value = value
for (action, value) in newState {
_value.updateValue(value, forKey: action)
}
return State(value: _value)
}
func set<T, U, A: ActionType>(action: A, f: (T?, A) -> U) -> State {
let key = action.key
let oldValue = value[key] as? T
let newValue = f(oldValue, action)
return merge([key: newValue])
}
func applyReducer(actions: [ActionType], combine: (State, ActionType) -> State) -> State {
return actions.reduce(self, combine: combine)
}
}
func actionReducer(state: State, action: ActionType) -> State {
switch action.key {
case .Name: return state.set(action as! NameAction, f: namer)
case .Counter: return state.set(action as! CounterAction, f: counter)
}
}
let actions: [ActionType] = [CounterAction.Increment, CounterAction.ChangeBy(100), NameAction.Set("John"), NameAction.Clear, NameAction.Set("Rob"), CounterAction.Increment]
actions.reduce(State(), combine: actionReducer).value
State().applyReducer(actions, combine: actionReducer).value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment