Created
June 27, 2019 22:38
-
-
Save Eluss/31bd886cda4efea404d29e4dc242372a to your computer and use it in GitHub Desktop.
Kickstart your app with lenses
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
struct Dog { | |
var name: String | |
} | |
struct Person { | |
var name: String | |
var age: Int | |
var dog: Dog | |
} | |
var dog = Dog(name: "Bark") | |
var person = Person(name: "Foo", age: 12, dog: dog) | |
struct Lens<Whole, Part> { | |
let get: (Whole) -> Part | |
let set: (Part) -> (Whole) -> Whole | |
} | |
extension Person { | |
enum lens { | |
static let dog: Lens<Person, Dog> = Lens( | |
get: { person in return person.dog }, | |
set: { newDog in | |
return { person in | |
var newPerson = person | |
newPerson.dog = newDog | |
return newPerson | |
} | |
}) | |
static let age: Lens<Person, Int> = Lens( | |
get: { person in return person.age}, | |
set: { newAge in | |
return { person in | |
var newPerson = person | |
newPerson.age = newAge | |
return newPerson | |
} | |
}) | |
static let name: Lens<Person, String> = Lens.init( | |
get: { whole in return whole.name }, | |
set: { newPart in { | |
oldWhole in | |
var whole = oldWhole | |
whole.name = newPart | |
return whole | |
}}) | |
} | |
} | |
extension Dog { | |
enum lens { | |
static let name: Lens<Dog, String> = Lens.init( | |
get: { whole in return whole.name }, | |
set: { newPart in { | |
oldWhole in | |
var whole = oldWhole | |
whole.name = newPart | |
return whole | |
}}) | |
} | |
} | |
//print(Person.lens.dog.get(person)) | |
//let newDog = Dog(name: "Reksio") | |
//let function: (Person) -> Person = Person.lens.dog.set(newDog) | |
//print(function(person)) | |
/// | |
/// | |
/// | |
precedencegroup PipelineOperator { | |
associativity: left | |
} | |
infix operator |> : PipelineOperator | |
func |> (lhs: Person, rhs: (Person) -> Person) -> Person { | |
return rhs(lhs) | |
} | |
let newPerson = person | |
|> Person.lens.name.set("Astek") | |
|> Person.lens.age.set(30) | |
|> Person.lens.dog.set(Dog(name: "Kik")) | |
//print(newPerson) | |
/// | |
precedencegroup SetOperator { | |
associativity: none | |
higherThan: PipelineOperator | |
} | |
infix operator .~ : SetOperator | |
infix operator %~ : SetOperator | |
extension Lens { | |
static func .~ (lhs: Lens<Whole, Part>, rhs: Part) -> (Whole) -> Whole { | |
return { whole in | |
return lhs.set(rhs)(whole) | |
} | |
} | |
static func %~ (lhs: Lens<Whole, Part>, rhs: @escaping (Part) -> Part) -> (Whole) -> Whole { | |
return { whole in | |
let part = lhs.get(whole) | |
let newPart = rhs(part) | |
let newWhole = lhs.set(newPart)(whole) | |
return newWhole | |
} | |
} | |
} | |
let newPerson2 = person | |
|> Person.lens.name .~ "Eliasz" | |
|> Person.lens.age %~ { age in return age * 2} | |
|> Person.lens.dog .~ Dog(name: "Olo") | |
print(newPerson2) | |
//Lens<A, B> + Lens<B, C> = Lens<A, C> | |
precedencegroup ChainOperator { | |
associativity: left | |
higherThan: SetOperator | |
} | |
infix operator .. : ChainOperator | |
//Whole | |
// Part | |
// Subpart | |
extension Lens { | |
static func .. <Subpart>(lhs: Lens<Whole, Part>, rhs: Lens<Part, Subpart>) -> Lens<Whole, Subpart> { | |
return Lens<Whole, Subpart>.init( | |
get: { whole in | |
let part = lhs.get(whole) | |
let subpart = rhs.get(part) | |
return subpart | |
}, | |
set: { newSubpart in | |
return { whole in | |
let part = lhs.get(whole) | |
let newPart = rhs.set(newSubpart)(part) | |
let newWhole = lhs.set(newPart)(whole) | |
return newWhole | |
} | |
}) | |
} | |
} | |
let dogsName: Lens<Person, String> = Person.lens.dog..Dog.lens.name | |
extension Person { | |
enum deepLens { | |
static let dogsName = Person.lens.dog..Dog.lens.name | |
} | |
} | |
let newPerson3 = person | |
|> Person.lens.name .~ "Test" | |
|> Person.lens.age %~ { age in return age * 2} | |
|> Person.deepLens.dogsName .~ "XX" | |
print(newPerson3) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment