Kickstart your app with lenses
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