2012-11-01 28 views
7

tôi muốn định nghĩa một kiểu lớp như thế này:Vấn đề với contravariance trong Scala

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

Tuy nhiên, vấn đề là khi tôi làm điều này tôi nhận được một Traversable[Any] và nó sẽ được tốt đẹp để có được một Traversable[Int] thay :

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

để làm cho vấn đề tồi tệ hơn, tôi không thể xác định một tiềm ẩn cho Traversable[Int] sau khi xác định một cho Traversable[_], bởi vì sau đó các định nghĩa sẽ c sử dụng sự mơ hồ. Sau khi kéo tóc ra, tôi đã từ bỏ.

Có cách nào để tôi có thể trả lại số tiền đó là Traversable[T] thay vì Traversable[Any] không?

Nhìn vào cách sum() được định nghĩa trên Seq trong thư viện Scala, tôi có thể nhìn thấy nó hoạt động với Numeric, đó là bất biến, nhưng tôi muốn triển khai mặc định cho siêu kiểu và có kết quả khác nhau hơn so với đầu vào (giống như các hoạt động gấp) thật tuyệt.

Trả lời

12

Cách duy nhất mà tôi biết để thêm các thông số loại đến các lớp học kiểu như vậy là sử dụng một def thay vì một 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

Oh wow, và làm việc! ... Tuy nhiên đó là một def mà trả về một thể hiện của đặc điểm bạn muốn và tôi đã được ấn tượng rằng paramicit tiềm ẩn phải là trường hợp cụ thể ... điều này là tuyệt vời :-) –

+0

vậy tại sao 'def' hoạt động và' ẩn đối tượng' không làm? – goral

+1

@goral: Vì 'đối tượng' không thể lấy tham số kiểu. – sschaef

Các vấn đề liên quan