gpt4 book ai didi

scala - 在 Scala 中合并两个 case 类,但具有深度嵌套的类型,没有镜头样板

转载 作者:行者123 更新时间:2023-12-03 23:35:38 24 4
gpt4 key购买 nike

类似于 this case class question但有一个转折:

我有一个案例类,它有一些深度嵌套的案例类作为属性。举个简单的例子,

case class Foo(fooPropA:Option[String], fooPropB:Option[Int])
case class Bar(barPropA:String, barPropB:Int)
case class FooBar(name:Option[String], foo:Foo, optionFoo: Option[Foo], bar:Option[Bar])

我想将两个 FooBar 案例类合并在一起,取输入存在的值并将它们应用于现有实例,生成更新版本:
val fb1 = FooBar(Some("one"), Foo(Some("propA"), None), Some(Foo(Some("propA"), Some(3))), Some(Bar("propA", 4)))
val fb2 = FooBar(None, Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), None)), None)
val merged = fb1.merge(fb2)
//merged = FooBar(Some("one"), Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), Some(3))), Some(Bar("propA", 4)))

我知道我可以使用镜头来组合深度嵌套的属性更新;但是,我觉得这将需要大量的样板代码:我需要为每个属性设置一个镜头,以及父类中的另一个组合镜头。即使在 shapeless 中使用更简洁的镜头创建方法,这似乎也需要维护很多。 .

棘手的部分是 optionFoo 元素:在这种情况下,两个元素都以 Some(value) 存在。但是,我想合并内部选项属性,而不仅仅是用 fb2 的新值覆盖 fb1。

我想知道是否有一种好的方法可以以需要最少代码的方式将这两个值合并在一起。我的直觉告诉我尝试使用 unapply case 类上的方法返回一个元组,迭代并将这些元组组合成一个新的元组,然后将该元组应用回一个 case 类。

有没有更有效的方法来做到这一点?

最佳答案

解决这个问题的一种干净的方法是将合并操作视为给定正确的幺半群实例的加法。你可以看到我的回答 here对于非常相似的问题的解决方案,但由于 the efforts,现在解决方案更加容易的typelevel团队。首先是案例类:

case class Foo(fooPropA: Option[String], fooPropB: Option[Int])
case class Bar(barPropA: String, barPropB: Int)
case class FooBar(name: Option[String], foo: Foo, bar: Option[Bar])

然后是一些样板(在即将发布的 Shapeless 2.0 版本中不需要):
import shapeless._

implicit def fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)
implicit def barIso = Iso.hlist(Bar.apply _, Bar.unapply _)
implicit def fooBarIso = Iso.hlist(FooBar.apply _, FooBar.unapply _)

为了清楚起见,我将稍微作弊,并为 Option 放置“第二个”幺半群实例。进入范围而不是使用标签:
import scalaz._, Scalaz._
import shapeless.contrib.scalaz._

implicit def optionSecondMonoid[A] = new Monoid[Option[A]] {
val zero = None
def append(a: Option[A], b: => Option[A]) = b orElse a
}

我们完成了:
scala> val fb1 = FooBar(Some("1"), Foo(Some("A"), None), Some(Bar("A", 4)))
fb1: FooBar = FooBar(Some(one),Foo(Some(propA),None),Some(Bar(propA,4)))

scala> val fb2 = FooBar(None, Foo(Some("updated"), Some(2)), None)
fb2: FooBar = FooBar(None,Foo(Some(updated),Some(2)),None)

scala> fb1 |+| fb2
res0: FooBar = FooBar(Some(1),Foo(Some(updated),Some(2)),Some(Bar(A,4)))

my previous answer一些额外的讨论。

关于scala - 在 Scala 中合并两个 case 类,但具有深度嵌套的类型,没有镜头样板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18026202/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com