使用Shapeless的方法需要的证据多于必要的证据

时间:2015-01-16 08:49:03

标签: scala shapeless

我昨天和几位同事一起探索了Shapeless,我们决定编写一个玩具方法,在案例类的第一个参数中添加一个,当该参数为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)
}

在我看来,ev2参数是多余的 - 当然可以推断E :: T =:= Int :: T,但编译器无法实现这一点。

有什么特别的原因吗?

1 个答案:

答案 0 :(得分:2)

你的直觉是合理的,但不幸的是,Scala编译器不够聪明,无法从ev2h派生ev。问题是h仅确定H分解为E :: T,它没有建立相反的结果,即ET合并为{ {1}}。

我能提出的最简洁的表述与你原来的相似,但只有一个证人,

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) } 消除E =:= Int证明h分解为R的证据。不过,我们仍然需要证明Int :: T等于Int :: T,以便使用更新后的元素返回R