2012-01-20 43 views
1

說我有Int小號演員(或者說:歸於)集合類型沒有指定類型參數

scala> val list = List(1, 2, 3, 4, 5) 
list: List[Int] = List(1, 2, 3, 4, 5) 

理所當然的List,Scala是足夠聰明返回正確的類型我。現在,考慮到,我對List的特定功能不感興趣,而是想要有一個更一般的(超)類型,比如Traversable。很明顯,我可以指定它:

scala> val trav = list: Traversable[Int] 
trav: Traversable[Int] = List(1, 2, 3, 4, 5) 

但這意味着我也必須重複類型參數。

這將無法正常工作

scala> list : Traversable 
<console>:9: error: type Traversable takes type parameters 
     list : Traversable 
      ^

而且這兩個例子刪除類型參數信息完全

scala> list : Traversable[T forSome {type T}] 
res2: Traversable[T forSome { type T }] = List(1, 2, 3, 4, 5) 

scala> list : Traversable[_] 
res3: Traversable[Any] = List(1, 2, 3, 4, 5) 

有沒有辦法得到一個Traversable[Int]不必鍵入Int

回答

4

你所要求的基本上是一個多態函數;或者是一個功能比較高的類型。您可以定義類型之間的這種映射* - > *如下:

scala> trait ~>[F[_], G[_]] { def map[A](f: F[A]): G[A] } 
defined trait $tilde$greater 

你會當然需要一個隱含的實例

scala> implicit object ListIsTrav extends (List ~> Traversable) { 
    | def map[A](l: List[A]): Traversable[A] = l 
    | } 
defined module ListIsTrav 

現在添加一個轉換器類形式的* - > *

scala> class Homomorphic[F[_], A](f: F[A]){ 
    | def as[G[_]](implicit ev: F ~> G): G[A] = ev map f 
    | } 
defined class Homomorphic 

scala> implicit def Type_Is_Homomorphic[F[_], A](f: F[A]) = new Homomorphic(f) 
Type_Is_Homomorphic: [F[_], A](f: F[A])Homomorphic[F,A] 

現在使用它:

scala> List(1, 2, 3).as[Traversable] 
res0: Traversable[Int] = List(1, 2, 3) 

這裏的痛苦是List ~> Traversable排序的隱式實例的指數爆炸。這在實踐中並不可行。

+0

不錯的答案! +1 –

+0

非常有見地。其實,我原本只對'F [A] <: Debilski

2

這個工程,但是很多工作,以避免打字Int ...也許有人可以想出一個更簡潔的技巧基於此。

scala> def traversableId[T](t: Traversable[T])= t 
traversableId: [T](t: Traversable[T])Traversable[T] 

scala> traversableId(list) 
res1: Traversable[Int] = List(1, 2, 3, 4, 5) 
0

寫相應的方法:

def asTraversable[T](x: Traversable[T]) = x 

asTraversable(x) 
0

集合類有最廣義特徵的轉換方法

scala> List(1,2,3).toTraversable 
res0: Traversable[Int] = List(1, 2, 3) 

scala> List(1,2,3).toIterable 
res1: Iterable[Int] = List(1, 2, 3) 

scala> List(1,2,3).toIndexedSeq 
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) 
+0

我知道。問題更多的是從語法的角度來看一般可能性。 – Debilski

1

雖然oxbow_lakes就如何解決這個問題的任意組合的一個great solution,他啓發了我對如何做到這一點的情況下Traversable是一個超級類型的List。 (這是不是在這個問題原先指定的,雖然)。

class CastToSuperType[F[_], A](f: F[A]) { 
    def as[G[_]](implicit ev: F[A] <:< G[A]): G[A] = f: G[A] 
} 

implicit def implCastToSuperType[F[_], A](f: F[A]) = new CastToSuperType(f) 

scala> List(1, 2, 3).as[Traversable] 
res0: Traversable[Int] = List(1, 2, 3) 

我猜想,類型的類型參數的任意數量的可能需要類型的lambda表達式,雖然。

+0

如果您想查看Map [String,List [Int]]作爲Map [String,Traversable [Int]],則需要輸入lambda表達式, –

0

在scala 2。10這是簡單得多,因爲引進.to[Col[_]],這是scala.collection.TraversableLike

的一部分

這裏的定義是:

def to[Col[_]](implicit cbf : scala.collection.generic.CanBuildFrom[scala.Nothing, A, Col[A]]) : Col[A] 

所以你基本上可以做到:

scala> List(1, 2, 3, 4, 5).to[Vector] 
res0: Vector[Int] = Vector(1, 2, 3, 4, 5) 


scala> List(1, 2, 3, 4, 5).to[Set] 
res1: Set[Int] = Set(5, 1, 2, 3, 4)