- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 shapeless 创建一个可以采用余积的 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
生成隐式变量,而不是 Indexable
>)
但是,如果我不使用 PolyApply 重载来应用 poly2,而是这样做:
def mergeWithExisting(existing: IndexedItem, item: Indexable): IndexedItem = {
item.foldLeft(existing)(updateCopy)
}
然后它就可以工作了。我不确定 Foldleft 正在做什么来解析类型。如果这是公认的方式,我该如何制作这个通用的以便我可以使用 Poly3?还是聚四?
有什么方法可以扩大 Poly 中的类型,使其与 apply 方法一起使用吗?也许我的处理方式是错误的,我愿意接受建议
最佳答案
为了左折叠具有 Poly2
的余积,该函数需要提供类型为 Case.Aux[A, x, A]
的情况,其中 A
是(固定)累加器类型,而 x
是余积中的每个元素。
对于累加器类型 updateCopy
和余积 IndexedItem
,您的 Indexable
正是执行此操作,因此您可以将带有初始值 Indexable
的 IndexedItem
左折叠以获得 IndexedItem
。如果我理解正确的话,这正是您想要的 - updateCopy
中独特的适当情况将应用于初始 IndexedItem
和余积的值,您将获得更新后的 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)
我个人认为这更具可读性 - 您可以将余积折叠为更新函数,然后将该函数应用于现有的 IndexedItem
。不过,这可能主要是风格问题。
您可以使用单个 Poly2
案例创建一个 Case.Aux[IndexedItem, Indexable, IndexedItem]
,这样您就可以直接使用 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, I] = at {
case ((a, log), b) => (a.copy(item2 = b), log :+ "2!")
}
implicit val caseItem3: Case.Aux[I, Item3, I] = at {
case ((a, log), 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),Item2(),Item3())
scala> example.foldLeft((existing, List.empty[String]))(updateCopyWithLog)
res0: (IndexedItem, List[String]) = (IndexedItem(Item1(10),Item2(),Item3()),List(1!))
如果这不是您所说的 Poly3
部分的意思,我很乐意扩展答案。
作为脚注, LeftFolder
source 建议 case 的输出类型可以与累加器类型不同,因为 tlLeftFolder
具有 OutH
类型参数。这对我来说似乎有点奇怪,因为据我所知, OutH
必然始终是 In
(如果您删除 OutH
并仅使用 In
,则 Shapeless 测试会通过)。我会仔细看看,也许会提出一个问题。
关于scala - 与 Poly 的联产品,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39927666/
我是一名优秀的程序员,十分优秀!