Skip to content

Instantly share code, notes, and snippets.

@southpawfishel
Created April 8, 2019 03:13
Show Gist options
  • Save southpawfishel/ef26c1a89d3d94bbb4796fc7707b3dee to your computer and use it in GitHub Desktop.
Save southpawfishel/ef26c1a89d3d94bbb4796fc7707b3dee to your computer and use it in GitHub Desktop.
public struct Lens<ParentType, ChildType> {
public let get: (ParentType) -> ChildType
public let set: (ParentType, ChildType) -> ParentType
}
public struct KeyLens<KeyType, ValueType> where KeyType: Hashable {
public typealias ParentType = [KeyType: ValueType]
public static func ForKey(_ key: KeyType) -> Lens<ParentType, ValueType> {
let lens = Lens<ParentType, ValueType>(
get: { dict in
return dict[key]!
},
set: { (dict, value) in
var newDict = dict
newDict[key] = value
return newDict
}
)
return lens
}
}
public struct IndexLens<ValueType> {
public typealias ArrayType = [ValueType]
public static func ForIndex(_ index: Int) -> Lens<ArrayType, ValueType> {
let lens = Lens<ArrayType, ValueType>(
get: { $0[index] },
set: { (arr, value) in arr.enumerated().map{ (i, element) in index == i ? value : element } }
)
return lens
}
}
precedencegroup ComposePrecedence {
associativity: left
}
infix operator ~> : ComposePrecedence
func ~> <ParentType, MiddleType, ChildType>(lhs: Lens<ParentType, MiddleType>, rhs: Lens<MiddleType, ChildType>) -> Lens<ParentType, ChildType> {
return Lens(
get: { parent in
let view = lhs.get(parent)
let child = rhs.get(view)
return child
},
set: { (parent, child) in
let initialView = lhs.get(parent)
let updatedView = rhs.set(initialView, child)
return lhs.set(parent, updatedView)
}
)
}
let todos = ["home": [ ["completed": false, "description": "cook"],
["completed": false, "description": "clean"]],
"work": [ ["completed": false, "description": "code"],
["completed": true, "description": "drink coffee"]]
];
print("starting todos:\n\(todos)\n")
let homeLens = KeyLens<String, [[String: Any]]>.ForKey("home")
let firstLens = IndexLens<[String: Any]>.ForIndex(0)
let completedLens = KeyLens<String, Any>.ForKey("completed")
let firstHomeCompletedLens = homeLens ~> firstLens ~> completedLens
print("first home item completed status: \(firstHomeCompletedLens.get(todos))\n")
print("after setting:\n\(firstHomeCompletedLens.set(todos, true))\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment