optics-dev / Monocle

Optics library for Scala

Home Page:https://www.optics.dev/Monocle/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

problem with sum type and focus

mtumilowicz opened this issue · comments

libs

I am using newest monocle

"dev.optics" %% "monocle-core" % "3.1.0",
"dev.optics" %% "monocle-macro" % "3.1.0",

with single import

import monocle.syntax.all._

and scala 2.13.10

problem

I would like to change email when PaymentMethod is PayPal (equivalent of copy)

val modified = user.copy(paymentMethod = user.paymentMethod match {
  case PayPal(_) => PayPal(newEmail)
  case dc@DebitCard(_,_,_) => dc
})

with quicklens I do simply

user.modify(_.paymentMethod.when[PayPal].email).setTo(newEmail)

and everything works, I would like to have something similar with monocle

code

case class User(name: String, paymentMethod: PaymentMethod)

sealed trait PaymentMethod
object PaymentMethod {
  case class PayPal(email: String) extends PaymentMethod

  case class DebitCard(
                        cardNumber: String,
                        expirationDate: YearMonth,
                        securityCode: Int
                      ) extends PaymentMethod
}

first try:

user.focus(_.paymentMethod.as[PayPal].email).replace(newEmail)

compilation error

value as is not a member of shared.user.PaymentMethod

another try:

user.focus(_.paymentMethod.focus().as[PayPal].email).replace(newEmail)

I get compilation error

value email is not a member of monocle.AppliedPrism[shared.user.PaymentMethod,shared.user.PaymentMethod.PayPal]

when I do something like this

val result: PaymentMethod = user
  .focus(_.paymentMethod.focus().as[PayPal].modify(_.focus(_.email).replace(newEmail)))
  .get

I get PaymentMethod as a return instead of User

however when I create everything by myself I get what I need

val newEmail = "newemail@gmail.com"
val setPaymentMethod = GenLens[User](_.paymentMethod)
val setPayPalEmail = Prism.partial[PaymentMethod, String]{case PayPal(x) => x}(PayPal)
val updatePayPalEmail = setPaymentMethod andThen setPayPalEmail
val result: User = updatePayPalEmail.replace(newEmail)(user)

how to do the same with focus?

@machisuji you would need to be using scala 3 to generate this optic.

Focus in scala 2 is much more limited. You can only using to generate lenses for fields inside a case class.