Created
August 22, 2015 16:59
-
-
Save rjchatfield/27e3d8ef2249a4298046 to your computer and use it in GitHub Desktop.
Inspired by Redux, but not really Redux
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
// 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