Skip to content

Instantly share code, notes, and snippets.

@naoty
Last active April 26, 2016 03:20
Show Gist options
  • Save naoty/174e958f94f7eda562d38786cc3f1862 to your computer and use it in GitHub Desktop.
Save naoty/174e958f94f7eda562d38786cc3f1862 to your computer and use it in GitHub Desktop.
import UIKit
struct Lens<A, B> {
private let getter: A -> B
private let setter: (A, B) -> A
init(getter: A -> B, setter: (A, B) -> A) {
self.getter = getter
self.setter = setter
}
}
extension Lens {
func get(from: A) -> B {
return getter(from)
}
func set(from: A, _ to: B) -> A {
return setter(from, to)
}
func modify(from: A, f: B -> B) -> A {
return set(from, f(get(from)))
}
}
extension Lens {
func compose<C>(other: Lens<B, C>) -> Lens<A, C> {
return Lens<A, C> (
getter: { (a: A) -> C in
other.get(self.get(a))
},
setter: { (a: A, c: C) -> A in
self.set(a, other.set(self.get(a), c))
}
)
}
}
infix operator >>> { associativity left }
func >>><A, B, C>(lens: Lens<A, B>, other: Lens<B, C>) -> Lens<A, C> {
return lens.compose(other)
}
let frameLens = Lens<UIView, CGRect>(getter: { $0.frame }, setter: { UIView(frame: $1) })
let sizeLens = Lens<CGRect, CGSize>(getter: { $0.size }, setter: { CGRect(origin: $0.origin, size: $1) })
let widthLens = Lens<CGSize, CGFloat>(getter: { $0.width }, setter: { CGSize(width: $1, height: $0.height) })
let heightLens = Lens<CGSize, CGFloat>(getter: { $0.height }, setter: { CGSize(width: $0.width, height: $1) })
let originLens = Lens<CGRect, CGPoint>(getter: { $0.origin }, setter: { CGRect(origin: $1, size: $0.size) })
let xLens = Lens<CGPoint, CGFloat>(getter: { $0.x }, setter: { CGPoint(x: $1, y: $0.y) })
let yLens = Lens<CGPoint, CGFloat>(getter: { $0.y }, setter: { CGPoint(x: $0.x, y: $1) })
let view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 500))
print(view) //=> <UIView: 0x7fb06bc18ba0; frame = (0 0; 300 500); layer = <CALayer: 0x7fb06bc06000>>
print((frameLens >>> sizeLens >>> widthLens).set(view, 100)) //=> <UIView: 0x7fb06bd22490; frame = (0 0; 100 500); layer = <CALayer: 0x7fb06bd21c30>>
print((frameLens >>> originLens >>> yLens).set(view, 50)) //=> <UIView: 0x7fb06bd26ff0; frame = (0 50; 300 500); layer = <CALayer: 0x7fb06bd24ee0>>
print((frameLens >>> sizeLens >>> heightLens).modify(view, f: { $0 * 2 })) //=> <UIView: 0x7fb06bf2b2d0; frame = (0 0; 300 1000); layer = <CALayer: 0x7fb06bf27ff0>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment