I have a need for modifying multiple fields of a case class without all the copy code. Seems shapeless is a good way to go.
According to example, I could use lens in this form:
lensA ~ lensB ~ lensC set(something)(valA, valB, valC)
which is good. However in my case, nested fields are not my biggest concern (I'm sure it will :-< ). So the lens solution is pretty much the same as:
something.copy(a = valA, b = valB, c = valC)
One thing I'd like to point out is that, not all the modifications are necessarily happened. In my pseudo case, I may update all a,b,c or some of them, or none, based on some if/elses within the context.
Therefore, Record with this kind of usage is pretty much what I need:
someHList + ('a ->> valA) + ('b ->> valB) + ('c ->> valC)
Even ultimately:
Seq(
'a ->> valA,
'b ->> valB,
'c ->> valC
).fold(someHList)(_ + _)
which is not possible according to my compiler (yield type mismatch error).
I know this usage only exists in my imagination, not documentation. However I'd really appreciate the correct way of using Record or lens or whatever to solve my problem. Any other elegant way is also welcomed!
THX!
There is already update single field operation + via the Updater operation provider and only thing you need is to apply it via some fold operation
So you can write
import shapeless._
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.Updater
import syntax.singleton._
import record._
object updateAll extends Poly2 {
implicit def updateOne[L <: HList, F](implicit update: Updater[L, F]) = at[L, F]((l, f) => update(l, f))
}
implicit class UpdateAllOps[L <: HList](record: L) {
def ++>[U <: HList](updates: U)(implicit fl: LeftFolder[U, L, updateAll.type]): fl.Out =
fl(updates, record)
}
now having
val rec = 'x ->> "Old" :: 'y ->> 1 :: HNil
val upd = 'z ->> true :: 'x ->> "New" :: HNil
You can verify that
rec ++> upd
Is same that
'x ->> "New" :: 'y ->> 1 :: 'z ->> true :: HNil
But important note that
val str = "New".asInstanceOf[String with Serializable]
rec ++> ('x ->> str :: HNil)
will result in something like
'x ->> "Old" :: y ->> 1 :: 'x -> "New" :: HNil
so you should be very careful with your types here, unless you define your own replacement for Updater
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With