Skip to content

Instantly share code, notes, and snippets.

@sjoerdvisscher
Last active February 24, 2016 23:19
Show Gist options
  • Save sjoerdvisscher/8a1085b5da129561ee41 to your computer and use it in GitHub Desktop.
Save sjoerdvisscher/8a1085b5da129561ee41 to your computer and use it in GitHub Desktop.
Mutating lenses in Swift using operators with inout arguments
struct Lens<T, A> {
let get: T -> A
let mod: (T, A -> A) -> T
func set(t: T, _ a: A) -> T {
return self.mod(t) { _ in a }
}
}
infix operator >>> {}
func >>><S, T, A>(l: Lens<S, T>, r: Lens<T, A>) -> Lens<S, A> {
return Lens(
get: { s in r.get(l.get(s)) },
mod: { s, f in l.mod(s) { t in r.mod(t, f) } }
)
}
struct Circle {
var r: Double
var c: Point
}
struct Point {
var x: Double
var y: Double
}
let center = Lens<Circle, Point>(
get: { c in c.c },
mod: { (var c, f) in c.c = f(c.c); return c }
)
let x = Lens<Point, Double>(
get: { p in p.x },
mod: { (var p, f) in p.x = f(p.x); return p }
)
let y = Lens<Point, Double>(
get: { p in p.y },
mod: { (var p, f) in p.y = f(p.y); return p }
)
infix operator ~ { associativity right precedence 90 }
func ~=<T, A>(l: Lens<T,A>, a: A) -> (Lens<T,A>, A) {
return (l, a)
}
func ~<T, A>(inout t: T, la: (Lens<T, A>, A)) {
t = la.0.set(t, la.1)
}
func ~<S, T, A>(l: Lens<S, T>, la: (Lens<T, A>, A)) -> (Lens<S, A>, A) {
return (l >>> la.0, la.1)
}
var circle = Circle(r: 1, c: Point(x: 5, y: 6))
circle ~ center ~ y ~= 4
circle ~ (center >>> x) ~= 3
print([circle.c.x, circle.c.y])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment