2012-11-01 93 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