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 { let get: (Whole) -> Part let set: (Part) -> (Whole) -> Whole } extension Person { enum lens { static let dog: Lens = 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 = 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 = 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 = 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, rhs: Part) -> (Whole) -> Whole { return { whole in return lhs.set(rhs)(whole) } } static func %~ (lhs: Lens, 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 + Lens = Lens precedencegroup ChainOperator { associativity: left higherThan: SetOperator } infix operator .. : ChainOperator //Whole // Part // Subpart extension Lens { static func .. (lhs: Lens, rhs: Lens) -> Lens { return Lens.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.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)