Я пытаюсь написать метод, который принимает любой тип коллекции CC[_]
и сопоставляет его с новой коллекцией (тот же тип коллекции, но с другим типом элемента), и я борюсь за права. В основном я пытаюсь реализовать map
, но не в самой коллекции.
Вопрос
Я пытаюсь реализовать метод с подписями, который выглядит примерно так:
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
, и меня интересует причина, по которой мои попытки (ниже) в конечном счете не сработали.
Мои попытки
(Для нетерпеливых, в дальнейшем, я полностью не могу заставить это работать. Повторить, вопрос: "Как я могу написать такой метод?" )
Я начинаю вот так:
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
^
Err, ОК! Возможно, если я действительно укажу этот экземпляр 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)
^
Err, ОК! Это более конкретная ошибка. Похоже, я могу это использовать!
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)
^
Скажите, что?
Наблюдения
Я действительно не могу не думать, что наблюдения Тони Морриса об этом в то время были абсолютно точными. Что он сказал? Он сказал: " Что бы это ни было, это не карта". Посмотрите, насколько это просто в стиле скаляз:
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]
Тогда
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)
^
Итак,
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] = [email protected]
scala> map(List(1, 2, 3, 4), (_ : Int).toString)
res5: List[java.lang.String] = List(1, 2, 3, 4)
Воспоминание о себе: слушать Тони!