julien-truffaut on gh-pages
Deploy website Deploy website … (compare)
xuwei-k on master
Update refined, refined-scalach… (compare)
julien-truffaut on gh-pages
Deploy website Deploy website … (compare)
xuwei-k on master
Update scalafmt-core to 3.5.2 (compare)
Good evening all!
I was wondering how can I improve upon this manual thing I'm doing now?
Suppose I have a case class Person(name: String, age: Int)
. I receive a PATCH
request, containing optional fields that may have changed. What I'm currently doing is manually building a bunch of Person => Person
functions, either copying over the new value or returning the given person
unchanged, then applying all those "patch" functions one after the other to the initial person
.
Surely there's a better way :slight_smile:
case class PatchPersonRequest(name: Option[String], age: Option[Int])
val request = PatchPersonRequest(...)
val patchName: Person => Person = request.name.fold[Person => Person](identity)(n => p => p.copy(name = n))
val patchAge: Person => Person = request.age.fold[Person => Person](identity)(a => p => p.copy(age = a))
...
val updatedPerson = Patch.merge(
person,
patchName,
patchAge
...
)
I'm using monocle to update deeply nested properties of person
, but even then this is manual and repetitive... and boilerplatey :(
Patch.merge
does a foldLeft
over the Seq[A => A]
, applying it to the initial A
...
fold
maybe you could use foldMapM
or other variants of foldMap
identity
I have a product type with optional types such as
case class Foo(bar1: Option[Bar1], bar2: Option[Bar2], bar3: Option[Bar3])
I will have a list of optional bar[i]s and I want to optionally modify my Foo
instance with them.
as it stands I have to repeat _.focus.replace
for each param. is there a way of abstracting it out? I tried doing that with something like:
def updateWith[T](f: Foo => Option[T]): ???
but I get:
Illegal field reference f; please use _.field1.field2... instead
is there a way of marking updateWith
somehow to make this go away?
_.focus(_.bar1).some.andThen(Focus[Bar1](_.xxx))
Thanks Julien. I think you misunderstood my issue: I don't care about the nested types in BarX
types here. I have maybeValues which I would like to update my model with, if they were Some()
initially I wanted to do something like:
List(
maybeBar1.map(updateWith),
maybeBar2.map(updateWith)
).reduceLeft(..)
with the updateWith
being responsible for the fold
needed but then I faced the problem I described.
but I just realised I would be equally happy with something like:
foo
.focus(_.bar1).replaceIfSome(maybeBar1)
.focus(_.bar2).replaceIfSome(maybeBar2)
with the function looking something like:
implicit class AppliedLensOps[A, C](lens: AppliedLens[A, Option[C]]) {
def replaceIfSome(maybe: Option[C]): A = maybe.fold(
lens.value
)( w =>
lens.replace(w.some)
)
}
is there a more generic way of doing this? :thinking
None
if it is a Some
?
@julien-truffaut I have the same problem as here: https://stackoverflow.com/a/42668525/9199853 I tried to replicate your answer with the updated API:
import monocle.macros.GenIso
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta])
val navigateToText = GenIso[Gamma, Option[Beta]]
.andThen(GenIso[Beta, Alpha].asPrism.below[Option])
.andThen(GenIso[Alpha, String].asPrism.below[Option])
it compiles. but if I add another field to Gamma
, say: maybeI: Option[Int]
it complains of:
Found several case class accessor for Gamma, Gamma needs to be a case class with a single accessor.
which makes sense now that I think about it. is there a way of solving the more generalised problem?
index
. Sorry for the noise again. I have to be careful that doesn't become a running gag.
GenLens[MyType](_.abc.def)
to build a lens for later usage, which works very very nice (Monocle 2.1.0 Scala 2.13).composeLens
with a lens and "identity lenses" I would expect no effect on the result after executing the "lens chain".GenLens[MyType](_)
without success, GenLens[MyType](identity)
does not compile, GenLens[MyType](x=>x)
does not compile too.