Привести (или, скорее: приписать) тип коллекции без указания параметра типа - PullRequest
1 голос
/ 20 января 2012

Скажите, у меня есть List из Int с

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

Конечно, 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?

Ответы [ 6 ]

4 голосов
/ 20 января 2012

То, что вы запрашиваете, является в основном полиморфной функцией;или функция над типами с более высоким родом.Вы можете определить такое отображение между типами * -> * следующим образом:

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

Теперь добавьте конвертер для типовform * -> *

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.Это не так удобно на практике.

2 голосов
/ 20 января 2012

Это работает, но много работы, чтобы избежать ввода 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)
1 голос
/ 20 января 2012

Хотя oxbow_lakes дал отличное решение о том, как решить эту проблему для произвольных комбинаций, он вдохновил меня на то, как это сделать для случая, когда 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)

Я подозреваю, что типам с произвольным числом параметров типа, возможно, понадобится лямбда-тип.

0 голосов
/ 29 сентября 2012

В 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)
0 голосов
/ 20 января 2012

Классы коллекции имеют методы преобразования для большинства обобщенных признаков

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 голосов
/ 20 января 2012

Напишите соответствующий метод:

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

asTraversable(x)
...