Scala中的逆变问题

时间:2012-11-01 12:05:05

标签: scala typeclass

我想定义一个这样的类型类:

trait CanFold[-T, R] {
  def sum(acc: R, elem: T): R
  def zero: R
}

implicit object CanFoldInts extends CanFold[Int, Int] {
  def sum(x: Int, y: Int) = x + y
  def zero = 0
}

implicit object CanFoldSeqs extends CanFold[Traversable[_], Traversable[_]] {
  def sum(x: Traversable[_], y: Traversable[_]) = x ++ y
  def zero = Traversable()
}

def sum[A, B](list: Traversable[A])(implicit adder: CanFold[A, B]): B = 
  list.foldLeft(adder.zero)((acc,e) => adder.sum(acc, e))

然而,问题是,当我这样做时,我得到Traversable[Any]并且它 很高兴获得Traversable[Int]代替:

 scala> sum(List(1,2,3) :: List(4, 5) :: Nil)
 res10: Traversable[Any] = List(1, 2, 3, 4, 5)

更糟糕的是,我无法定义一个隐含的 在为Traversable[Int]定义一个之后Traversable[_],因为那样 这些定义会引起歧义。把我的头发拉出后我 放弃了。

有什么办法可以让这笔钱归来 Traversable[T]代替Traversable[Any]

看看如何在Scala库中的sum()上定义Seq,我可以看到它与Numeric一起使用,它是不变的,但我想要超类型的默认实现并获得结果与输入不同(与折叠操作相同)很不错。

1 个答案:

答案 0 :(得分:12)

我知道将类型参数添加到此类型类的唯一方法是使用def而不是object

implicit def CanFoldSeqs[A] = new CanFold[Traversable[A], Traversable[A]] {
  def sum(x: Traversable[A], y: Traversable[A]) = x ++ y
  def zero = Traversable()
}

scala> sum(List(1, 2, 3) :: List(4, 5) :: Nil)
res0: Traversable[Int] = List(1, 2, 3, 4, 5)