Skip to content

Instantly share code, notes, and snippets.

@gseitz
Forked from retronym/lensed.scala
Created September 24, 2011 12:59
Show Gist options
  • Save gseitz/1239304 to your computer and use it in GitHub Desktop.
Save gseitz/1239304 to your computer and use it in GitHub Desktop.
Lensed
// see https://github.com/gseitz/Lensed
object Lensed {
import scalaz._
import Scalaz._
case class Address(street: String, number: Int)
case class Person(name: String, address: Address)
object Person {
// currently generated
val name: Lens[Person, String] = Lens(_.name, (p, n) => p.copy(name = n))
val address: Lens[Person, Address] = Lens(_.address, (p, a) => p.copy(address = a))
// proposed
class PimpedLens[A](l: Lens[A, Person]) {
val name: Lens[A, String] = l andThen Person.name
val address: Lens[A, Address] = l andThen Person.address
}
implicit def pimpLens[A](l: Lens[A, Person]) = new PimpedLens(l)
}
object Address {
// Generated
val street: Lens[Address, String] = Lens(_.street, (p, s) => p.copy(street = s))
val number: Lens[Address, Int] = Lens(_.number, (a, n) => a.copy(number = n))
// proposed
class PimpedLens[A](l: Lens[A, Address]) {
val street: Lens[A, String] = l andThen Address.street
val number: Lens[A, Int] = l andThen Address.number
}
implicit def pimpLens[A](l: Lens[A, Address]) = new PimpedLens(l)
class ZipLens[A](l: Lens[A, Address], state: State[Address, Address]) {
def street(s: String) = new ZipLens(l, state.map(Address.street.set(_, s)))
def number(n: Int) = new ZipLens(l, state.map(Address.number.set(_, n)))
def unfocus(a: A) = l.set(a, state ! l.get(a))
}
implicit def zipLens[A](l: Lens[A, Address]) = new {
def focus = new ZipLens(l, init[Address])
}
}
val p = Person("Brent", Address("Main St", 17))
Person.address.street.set(p, "Lower Main St")
Person.address.focus.street("Not-So-Main St").number(42).unfocus(p)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment