Skip to content

Instantly share code, notes, and snippets.

@richashworth richashworth/
Last active Jun 25, 2017

What would you like to do?
import $ivy.`com.github.julien-truffaut::monocle-core:1.4.0`, monocle.Lens
import $ivy.`com.github.julien-truffaut::monocle-macro:1.4.0`, monocle.macros.GenLens
// _.copy fine for simple cases
case class Address(line1: String, line2: String, postcode: String)
val a = Address("221B", "Baker St", "NW1 6XE")
println(a.copy(line1 = "221A"))
// Becomes more tedious for nested classes
case class Account(ID: Int, owner: Person)
case class Person(name: String, address: Address)
val p = Person("Sherlock Holmes", a)
val acc1 = Account(1, p)
val acc2 = acc1.copy(
owner = acc1.owner.copy(
address = acc1.owner.address.copy(
line1 = "221A")))
// Enter Lenses
val owner: Lens[Account, Person] = GenLens[Account](_.owner)
val address: Lens[Person, Address] = GenLens[Person](_.address)
val line1: Lens[Address, String] = GenLens[Address](_.line1)
// Real power lies in composing lenses
val lens: Lens[Account, String] = owner composeLens address composeLens line1
import $ivy.`com.github.julien-truffaut::monocle-core:1.4.0`, monocle.{Lens, Optional}
import $ivy.`com.github.julien-truffaut::monocle-macro:1.4.0`, monocle.macros.GenLens
import $file.Lenses, Lenses.Address
// Change our domain model so that account owners do not need to provide an address
case class Person(name: String, maybeAddress: Option[Address])
case class Account(ID: Int, owner:Person)
// Set up some example data
val a = Address("221B", "Baker St", "NW1 6XE")
val p1 = Person("John Watson", None)
val p2 = Person("Sherlock Holmes", Some(a))
val acc = Account(1, p1)
// As before, we can define a lens between account and its owner
val owner = GenLens[Account](_.owner)
// Use `Optional` to manipulate fields of type Option[_].
// Takes two functions as arguments: a 'getter' and a 'setter'
val address = Optional[Person, Address](_.maybeAddress)(a => _.copy(maybeAddress = Some(a)))
// Lenses and Optionals compose
val optional: Optional[Account, Address] = owner composeOptional address
val updatedAcc = optional.set(a)(acc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.