【发布时间】:2012-08-25 15:40:40
【问题描述】:
我正在尝试编写一个方法来接受任何类型的集合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 的情况下也适用的答案感兴趣,并且我对我的尝试(如下)最终没有成功的原因感兴趣。
我的尝试
(对于不耐烦的人,在接下来的内容中,我完全无法让它发挥作用。重申一下,问题是“我怎样才能编写这样的方法?”) em>
我是这样开始的:
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 风格中是多么容易:
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)
给自己的备忘录:听托尼的!
【问题讨论】:
-
那么问题是什么?
-
问题是——我怎样才能写出这样的方法?我们中的一些人试图表明我们已经努力自己回答这个问题!我为 tl;dr 集添加了一个编辑
-
...而我如此接近。已经在推特上回答了。我会等着看它是否在这里出现......
-
TraversableOnce的map不是函子映射,但话又说回来,它从未假装是函子映射。它的设计目标明确排除了它成为函子映射。 -
丹尼尔:我不否认。我只是指出,使用它非常难以处理。坦率地说,我应该能够自己回答这个问题
标签: scala collections