我昨天和一些同事一起探索了Shapeless,我们决定编写一个玩具方法,将一个添加到case类的第一个参数,当该参数为Int:
def addOneToCaseClass[C, H <: HList, E, T <: HList]
(c: C)
(implicit gen: Generic.Aux[C, H],
h: IsHCons.Aux[H, E, T],
ev: E =:= Int,
ev2: (Int :: T) =:= H
): C = {
val hList = gen.to(c)
val elem = hList.head
val tail = hList.tail
val newElem = elem + 1
gen.from(newElem :: tail)
}
Run Code Online (Sandbox Code Playgroud)
在我看来,ev2参数是多余的 - 当然可以推断出E :: T =:= Int :: T,但编译器无法实现这一点.
有什么特别的原因吗?
您的直觉是合理的,但不幸的是 Scala 编译器不够聪明,无法ev2从h和派生ev。问题是h只建立了H分解为E :: T,而没有建立逆过程,即E和T结合为等于H。
我能想到的最简洁的表述与你原来的相似,但少了一个见证人,
def addOneToCaseClass[C, R <: HList, T <: HList](c: C)
(implicit
gen: Generic.Aux[C, R],
h: IsHCons.Aux[R, Int, T],
ev: (Int :: T) =:= R) = {
val hList = gen.to(c)
val elem = hList.head
val tail = hList.tail
gen.from(elem+1 :: tail)
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们可以消除证明,E =:= Int通过使用h来证明R分解为Int :: T。然而,我们仍然需要证明这Int :: T等于R向后移动gen更新的元素。
| 归档时间: |
|
| 查看次数: |
139 次 |
| 最近记录: |