2012-11-01 53 views
7

逆变问题我想这样定义一个类型级:在斯卡拉

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]

寻找如何sum()在Scala的库中Seq定义,我可以看到它的工作原理与Numeric,这是不变的,但我要为超类型的默认实现,并具有结果比输入不同(与折叠操作)很好。

回答

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) 
+0

哇哦,那作品! ......然而,它是一个def,它返回你想要的特性的一个实例,我的印象是隐含的参数必须是具体的实例......这真棒:-) –

+0

那么为什么'def'工作和'隐式对象'才不是? – goral

+1

@goral:因为'object'不能携带类型参数。 – sschaef