Работа с коллекциями Scala - CanBuild от проблем

Я пытаюсь написать метод, который принимает коллекцию любого типа.CC[_] и сопоставляет его с новой коллекцией (того же типа коллекции, но другого типа элемента), и я борюсь по-королевски. В основном я пытаюсь реализоватьmap ноnot on the collection itself.

The Question

Я пытаюсь реализовать метод с подписью, которая выглядит примерно так:

def map[CC[_], T, U](cct: CC[T], f: T => U): CC[U]

Его использование будет:

map(List(1, 2, 3, 4), (_ : Int).toString) //would return List[String]

Я заинтересован в ответе, который также работал бы там, гдеCC являетсяArray и меня интересует причина, по которой мои попытки (см. ниже) в конечном итоге не сработали.

My Attempts

(For the impatient, in what follows, I utterly fail to get this to work. To reiterate, the question is "how can I write such a method?")

Я начинаю так:

scala> def map[T, U, CC[_]](cct: CC[T], f: T => U)(implicit cbf: CanBuildFrom[CC[T], U, CC[U]]): CC[U] = 
     | cct map f
                                                             ^
 <console>:9: error: value map is not a member of type parameter CC[T]
       cct map f
           ^

Хорошо, это имеет смысл - я должен сказать, чтоCC это проходимо!

scala> def map[T, U, X, CC[X] <: Traversable[X]](cct: CC[T], f: T => U)(implicit cbf: CanBuildFrom[CC[T], U, CC[U]]): CC[U] = 
     | cct map f
<console>:10: error: type mismatch;
 found   : Traversable[U]
 required: CC[U]
       cct map f
           ^

Оу, хорошо! Может быть, если я действительно укажу этоcbf пример. Ведь он указывает тип возвращаемого значения (To) какCC[U]:

scala> def map[T, U, X, CC[X] <: Traversable[X]](cct: CC[T], f: T => U)(implicit cbf: CanBuildFrom[CC[T], U, CC[U]]): CC[U] = 
     | cct.map(t => f(t))(cbf)
<console>:10: error: type mismatch;
 found   : scala.collection.generic.CanBuildFrom[CC[T],U,CC[U]]
 required: scala.collection.generic.CanBuildFrom[Traversable[T],U,CC[U]]
       cct.map(t => f(t))(cbf)
                          ^

Оу, хорошо! Это более конкретная ошибка. Похоже, я могу это использовать!

scala> def map[T, U, X, CC[X] <: Traversable[X]](cct: CC[T], f: T => U)(implicit cbf: CanBuildFrom[Traversable[T], U, CC[U]]): CC[U] = 
     | cct.map(t => f(t))(cbf)
map: [T, U, X, CC[X] <: Traversable[X]](cct: CC[T], f: T => U)(implicit cbf: scala.collection.generic.CanBuildFrom[Traversable[T],U,CC[U]])CC[U]

Brilliant. У меня естьmap! Давайте использовать эту вещь!

scala> map(List(1, 2, 3, 4), (_ : Int).toString)
<console>:11: error: Cannot construct a collection of type List[java.lang.String] with elements of type java.lang.String based on a collection of type Traversable[Int].
              map(List(1, 2, 3, 4), (_ : Int).toString)
                 ^

Чего-чего?

Observations

I really can't help but think that Tony Morris' observations about this at the time were absolutely spot on. What did he say? He said "Whatever that is, it is not map". Look at how easy this is in scalaz-style:

scala> trait Functor[F[_]] { def fmap[A, B](fa: F[A])(f: A => B): F[B] }
defined trait Functor

scala> def map[F[_]: Functor, A, B](fa: F[A], f: A => B): F[B] = implicitly[Functor[F]].fmap(fa)(f)
map: [F[_], A, B](fa: F[A], f: A => B)(implicit evidence$1: Functor[F])F[B]

Then

scala> map(List(1, 2, 3, 4), (_ : Int).toString)
<console>:12: error: could not find implicit value for evidence parameter of type Functor[List]
              map(List(1, 2, 3, 4), (_ : Int).toString)
                 ^

So that

scala> implicit val ListFunctor = new Functor[List] { def fmap[A, B](fa: List[A])(f: A => B) = fa map f }
ListFunctor: java.lang.Object with Functor[List] = $anon$1@4395cbcb

scala> map(List(1, 2, 3, 4), (_ : Int).toString)
res5: List[java.lang.String] = List(1, 2, 3, 4)

Памятка для себя:listen to Tony!

Ответы на вопрос(3)

Ваш ответ на вопрос