Last active
December 18, 2016 06:15
-
-
Save ukitaka/319dda356621b71e43ccca25229925e3 to your computer and use it in GitHub Desktop.
Lens
This file contains hidden or 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 Lens<S, A> { | |
| typealias Getter = (S) -> A | |
| typealias Setter = (S, A) -> S | |
| fileprivate let _get: Getter | |
| fileprivate let _set: Setter | |
| init(get: @escaping Getter, set: @escaping Setter) { | |
| self._get = get | |
| self._set = set | |
| } | |
| func get(_ s: S) -> A { | |
| return _get(s) | |
| } | |
| func set(_ s: S) -> (A) -> S { | |
| return curry(_set)(s) | |
| } | |
| func modify(_ s: S) -> ((A) -> A) -> S { | |
| return { f in | |
| self.set(s)(f(self.get(s))) | |
| } | |
| } | |
| } | |
| // MARK: - | |
| precedencegroup MonadicPrecedenceRight { | |
| associativity: right | |
| higherThan: AssignmentPrecedence | |
| } | |
| infix operator >=>: MonadicPrecedenceRight | |
| func >=> <A, B, C>(lhs: Lens<A, B>, rhs: Lens<B, C>) -> Lens<A, C> { | |
| return Lens<A, C>( | |
| get: { a in | |
| rhs.get(lhs.get(a)) | |
| }, | |
| set: { (a, c) -> A in | |
| lhs.set(a)(rhs.set(lhs.get(a))(c)) | |
| } | |
| ) | |
| } | |
| // MARK: - | |
| func curry<A, B>(_ function: @escaping (A) -> B) -> (A) -> B { | |
| return { (a: A) -> B in function(a) } | |
| } | |
| func curry<A, B, C>(_ function: @escaping (A, B) -> C) -> (A) -> (B) -> C { | |
| return { (a: A) -> (B) -> C in { (b: B) -> C in function(a, b) } } | |
| } |
This file contains hidden or 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 Employee { | |
| let name: String | |
| let company: Company | |
| } | |
| struct Company { | |
| let name: String | |
| let address: Address | |
| } | |
| struct Address { | |
| let city: String | |
| let street: Street | |
| } | |
| struct Street { | |
| let number: Int | |
| let name: String | |
| } | |
| // MARK: - | |
| let employeeCompanyLens = Lens<Employee, Company>( | |
| get: { employee in | |
| employee.company | |
| }, | |
| set: { employee, company in | |
| Employee(name: employee.name, company: company) | |
| } | |
| ) | |
| let companyAddressLens = Lens<Company, Address>( | |
| get: { company in | |
| company.address | |
| }, | |
| set: { company, address in | |
| Company(name: company.name, address: address) | |
| } | |
| ) | |
| let addressStreetLens = Lens<Address, Street>( | |
| get: { address in | |
| address.street | |
| }, | |
| set: { address, street in | |
| Address(city: address.city, street: street) | |
| } | |
| ) | |
| let streetNumberLens = Lens<Street, Int>( | |
| get: { street in | |
| street.number | |
| }, | |
| set: { street, number in | |
| Street(number: number, name: street.name) | |
| } | |
| ) | |
| // MARK: - | |
| let employeeCompanyAddressStreetNumberLens | |
| = employeeCompanyLens >=> companyAddressLens >=> addressStreetLens >=> streetNumberLens |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment