Skip to content

Instantly share code, notes, and snippets.

@Eluss Eluss/lenses.swift
Created Jun 27, 2019

Embed
What would you like to do?
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
You can’t perform that action at this time.