如何理解traverse,traverseU和traverseM

Xia*_*ong 37 scala scalaz

我对traverse,traverseU和traverseM的使用案例感到困惑,我在scalaz网站上搜索了它,简单的代码示例:

 def sum(x: Int) = x + 1

 List(1,2,3).traverseU(sum)
Run Code Online (Sandbox Code Playgroud)

看起来它类似于(地图和聚合):

List(1,2,3).map(sum).reduceLeft(_ + _)
Run Code Online (Sandbox Code Playgroud)

我认为它不仅仅是针对traverseU,我只是想知道这三种方法之间有什么区别,我会有更好的示例代码来显示差异

提前谢谢了

lmm*_*lmm 70

sequence用来聚集应用效果.更具体地说,它可以让你"炫" F[G[A]]G[F[A]],只要GApplicativeFTraversable.所以我们可以用它来"拉"一堆Applicative效果(注意所有Monad的都是Applicative):

List(Future.successful(1), Future.successful(2)).sequence : Future[List[Int]]
// = Future.successful(List(1, 2))
List(4.set("abc"), 5.set("def")).sequence : Writer[String, List[Int]]
// = List(4, 5).set("abcdef")
Run Code Online (Sandbox Code Playgroud)

traverse等同于map当时sequence,所以你可以在有一个函数返回一个函数时使用它,你Applicative只想得到一个你的单个实例Applicative而不是它们的列表:

def fetchPost(postId: Int): Future[String]
//Fetch each post, but we only want an overall `Future`, not a `List[Future]`
List(1, 2).traverse[Future, String](fetchPost): Future[List[String]]
Run Code Online (Sandbox Code Playgroud)

traverseU是一样的操作traverse,只是表达不同的类型,以便编译器可以更容易地推断它们.

def logConversion(s: String): Writer[Vector[String], Int] =
  s.toInt.set(Vector(s"Converted $s"))
List("4", "5").traverseU(logConversion): Writer[Vector[String], List[Int]]
// = List("4", "5").map(logConversion).sequence
// = List(4.set("Converted 4"), 5.set("Converted 5")).sequence
// = List(4, 5).set(Vector("Converted 4", "Converted 5"))
Run Code Online (Sandbox Code Playgroud)

traverseM(f)相当于traverse(f).map(_.join),joinscalaz名称的位置flatten.它作为一种"提升平面地图"非常有用:

def multiples(i: Int): Future[List[Int]] =
  Future.successful(List(i, i * 2, i * 3))
List(1, 10).map(multiples): List[Future[List[Int]]] //hard to work with
List(1, 10).traverseM(multiples): Future[List[Int]]
// = List(1, 10).traverse(multiples).map(_.flatten)
// = List(1, 10).map(multiples).sequence.map(_.flatten)
// = List(Future.successful(List(1, 2, 3)), Future.successful(List(10, 20, 30)))
//     .sequence.map(_.flatten)
// = Future.successful(List(List(1, 2, 3), List(10, 20, 30))).map(_.flatten)
// = Future.successful(List(1, 2, 3, 10, 20, 30))
Run Code Online (Sandbox Code Playgroud)

  • 是的,这是唯一的区别.(从技术上讲,它使用额外的参数来执行推理,但我希望JVM能够优化它).如果`traverseU`*没有*推断类型参数并且您需要手动指定它们(或者如果您正在编写通用代码,而您正在遍历的类型本身就是一个类型参数),则更容易使用`traverse`(没有推理助手),但我认为这是你唯一想要使用`traverse`而不是`traverseU`的情况. (2认同)