我正在尝试编写一个接受任何类型集合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
^
错,好!也许如果我真的指定了那个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]
杰出的。我有我一个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)
^
说什么?
观察
我真的不禁认为托尼莫里斯当时对此的观察绝对是正确的。他说什么?他说“不管是什么,它都不是地图”。看看这在 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]
然后
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] = $anon$1@4395cbcb
scala> map(List(1, 2, 3, 4), (_ : Int).toString)
res5: List[java.lang.String] = List(1, 2, 3, 4)
给自己的备忘录:听托尼的!