Skip to content

Instantly share code, notes, and snippets.

@fancellu
Created April 28, 2020 14:29
Show Gist options
  • Save fancellu/a5288e1967809f67e051a5ded21575f8 to your computer and use it in GitHub Desktop.
Save fancellu/a5288e1967809f67e051a5ded21575f8 to your computer and use it in GitHub Desktop.
Example usage of the Monocle Optics library showing manipulation of deeply nested immutable objects
import monocle.{Iso, Prism}
import monocle.macros.syntax.lens._
import monocle.macros.GenIso
object LensApp extends App{
case class Street(number: Int, name: String)
case class Address(city: String, street: Street, postcode: Option[String]=None)
case class Company(name: String, address: Address)
sealed trait Gender
case object Male extends Gender
case object Female extends Gender
case class Other(v: String) extends Gender
case class Employee(name: String, gender: Gender, company: Company)
val genderString = Prism.partial[Gender, String]{
case Other(v) => s"gender: $v"
case Male=> "man"
case Female=> "woman"
}(Other)
val employee = Employee("Alan", Other("Apache Attack Helicopter"), Company("Twitter", Address("London", Street(12, "high street"))))
println(employee)
val genderOption=employee.lens(_.gender).composePrism(genderString).getOption
println(genderOption)
val employeePostcode: Option[String] =employee.lens(_.company.address.postcode).get
println(s"employeePostcode=$employeePostcode")
println("We update employee")
val updatedemployee: Employee =employee.lens(_.company.address.street.name).modify(_.toUpperCase)
.lens(_.company.address.postcode).set(Some("KT18 4AL"))
.lens(_.name).set("james")
.lens(_.gender).set(Male)
println(updatedemployee)
val genderOption2=updatedemployee.lens(_.gender).composePrism(genderString).getOption
println(genderOption2)
val updatedemployeeAddress: Address =updatedemployee.lens(_.company.address).get
println(updatedemployeeAddress)
// define isomorphic mapping from tuple to case class, and case class to tuple
val streetToTuple = Iso[Street, (Int, String)](st => (st.number, st.name)){case (number, name) => Street(number, name)}
val streetToTupleCase = Iso[Street, (Int, String)](Street.unapply(_).get)(Street.tupled)
val streetToTupleGen = GenIso.fields[Street]
println(streetToTuple(23,"ISO Lane"))
println(streetToTupleCase(24,"ISO Lane"))
println(streetToTupleGen(25,"ISO Lane"))
val updatedemployeePostcode: Option[String] =updatedemployee.lens(_.company.address.postcode).get
println(s"updatedemployeePostcode=$updatedemployeePostcode")
val street: Street =updatedemployee.lens(_.company.address.street).get
println(street)
println(streetToTupleCase.get(street))
val streetTuple: (Int, String) =updatedemployee.lens(_.company.address.street).composeIso(streetToTupleCase).get
println(streetTuple)
}
Employee(Alan,Other(Apache Attack Helicopter),Company(Twitter,Address(London,Street(12,high street),None)))
Some(gender: Apache Attack Helicopter)
employeePostcode=None
We update employee
Employee(james,Male,Company(Twitter,Address(London,Street(12,HIGH STREET),Some(KT18 4AL))))
Some(man)
Address(London,Street(12,HIGH STREET),Some(KT18 4AL))
Street(23,ISO Lane)
Street(24,ISO Lane)
Street(25,ISO Lane)
updatedemployeePostcode=Some(KT18 4AL)
Street(12,HIGH STREET)
(12,HIGH STREET)
(12,HIGH STREET)
Process finished with exit code 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment