加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 与Poly的Coproduct

发布时间:2020-12-16 18:34:38 所属栏目:安全 来源:网络整理
导读:我正在尝试使用无形来创建一个可以带有副产品的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 :+
我正在尝试使用无形来创建一个可以带有副产品的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)
  }
}

这给了我一个错误

Error:(48,15) could not find implicit value for parameter cse:
shapeless.poly.Case[samples.IndexUpdater.updateCopy.type,shapeless.::[samples.IndexedItem,shapeless.::[samples.IndexUpdater.Indexable,shapeless.HNil]]]
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部分的意思,我很乐意扩展答案.

作为脚注,LeftFolder source表明案例的输出类型与累加器类型不同,因为tlLeftFolder具有OutH类型参数.这对我来说有点奇怪,因为据我所知,OutH必然总是In(如果你移除OutH并且只使用In,则无形测试通过).我会仔细看看,也许会打开一个问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读