Skip to content

Instantly share code, notes, and snippets.

@richashworth
Last active June 25, 2017 22:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richashworth/44ec843872437ce6c10539fde42df51f to your computer and use it in GitHub Desktop.
Save richashworth/44ec843872437ce6c10539fde42df51f to your computer and use it in GitHub Desktop.
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)
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")))
println(acc2)
// 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)
println(owner.get(acc1))
println(line1.set("221A")(a))
// Real power lies in composing lenses
val lens: Lens[Account, String] = owner composeLens address composeLens line1
println(lens.get(acc1))
println(lens.set("221A")(acc1))
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)))
println(address.getOption(p1))
println(address.getOption(p2))
println(address.set(a)(p1))
// Lenses and Optionals compose
val optional: Optional[Account, Address] = owner composeOptional address
println(optional.getOption(acc))
val updatedAcc = optional.set(a)(acc)
println(updatedAcc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment