scala – 与Poly的Coproduct
我正在尝试使用无形来创建一个可以带有副产品的poly2函数:
case class IndexedItem( item1: Item1,item2: Item2,item3: Item3 ) case class Item1(name: Int) case class Item2() case class Item3() object IndexUpdater { type Indexable = Item1 :+: Item2 :+: Item3 :+: CNil object updateCopy extends Poly2 { implicit def caseItem1 = at[IndexedItem,Item1] { (a,b) => a.copy(item1 = b) } implicit def caseItem2 = at[IndexedItem,Item2] { (a,b) => a.copy(item2 = b) } implicit def caseItem3 = at[IndexedItem,Item3] { (a,b) => a.copy(item3 = b) } } def mergeWithExisting(existing: IndexedItem,item: Indexable): IndexedItem = { updateCopy(existing,item) } } 这给了我一个错误
鉴于Poly2正在处理项目的实例,而不是扩展的副产品类型(即为Item1生成了implicits而不是Indexable),我认为这是有道理的 但是,如果我不将poly2应用于PolyApply重载,而是执行: def mergeWithExisting(existing: IndexedItem,item: Indexable): IndexedItem = { item.foldLeft(existing)(updateCopy) } 然后它确实有效.我不确定foldleft正在做什么,以便类型解决.如果这是可接受的方式,我该如何制作这种通用的,以便我可以使用Poly3?还是Poly4? 是否有任何方法可以扩展poly中的类型以使其与apply方法一起使用?也许我会以错误的方式解决这个问题,我愿意接受建议 解决方法
为了使具有Poly2的副产品折叠,该函数需要提供Case.Aux [A,x,A]类型的情况,其中A是(固定的)累加器类型,x是副产品中的每个元素.
您的updateCopy对累加器类型IndexedItem和coproduct Indexable执行此操作,因此您可以使用初始IndexedItem折叠一个Indexable来获取IndexedItem.如果我理解正确,这正是您想要的 – updateCopy中唯一合适的案例将应用于初始IndexedItem和coproduct的值,您将获得更新的IndexedItem. 将此操作视为“左侧折叠”有点不直观,您可以将其写为普通折叠,将副产品简单地折叠为值. object updateCopy extends Poly1 { type U = IndexedItem => IndexedItem implicit val caseItem1: Case.Aux[Item1,U] = at[Item1](i => _.copy(item1 = i)) implicit val caseItem2: Case.Aux[Item2,U] = at[Item2](i => _.copy(item2 = i)) implicit val caseItem3: Case.Aux[Item3,U] = at[Item3](i => _.copy(item3 = i)) } 然后: def mergeWithExisting(existing: IndexedItem,item: Indexable): IndexedItem = item.fold(updateCopy).apply(existing) 我个人认为这更具可读性 – 您将coproduct折叠到更新函数,然后将该函数应用于现有的IndexedItem.不过,这可能主要是风格问题. 您可以使用单个Case.Aux [IndexedItem,Indexable,IndexedItem]创建一个Poly2,它允许您直接使用apply,但这比其中一个折叠方法更加冗长且不那么惯用(此时您也不会甚至需要一个多态函数值 – 你可以只使用普通的(IndexedItem,Indexable)=> IndexedItem). 最后,我不确定你将折叠方法扩展到Poly3等是什么意思,但如果你想要的是提供额外的初始值进行转换,那么你可以使累加器类型为元组(或Tuple3,等等.).例如: object updateCopyWithLog extends Poly2 { type I = (IndexedItem,List[String]) implicit val caseItem1: Case.Aux[I,Item1,I] = at { case ((a,log),b) => (a.copy(item1 = b),log :+ "1!") } implicit val caseItem2: Case.Aux[I,Item2,b) => (a.copy(item2 = b),log :+ "2!") } implicit val caseItem3: Case.Aux[I,Item3,b) => (a.copy(item3 = b),log :+ "2!") } } 然后: scala> val example: Indexable = Coproduct(Item1(10)) example: Indexable = Inl(Item1(10)) scala> val existing: IndexedItem = IndexedItem(Item1(0),Item2(),Item3()) existing: IndexedItem = IndexedItem(Item1(0),Item3()) scala> example.foldLeft((existing,List.empty[String]))(updateCopyWithLog) res0: (IndexedItem,List[String]) = (IndexedItem(Item1(10),Item3()),List(1!)) 如果那不是您对Poly3部分的意思,我很乐意扩展答案. 作为脚注, (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |