web-dev-qa-db-fra.com

Comment comprendre traverse, traverseU et traverseM

Je suis confus au sujet du cas d'utilisation de traverse, traverseU et traverseM, je l'ai recherché sur le site Web de scalaz, l'exemple de code simple:

 def sum(x: Int) = x + 1

 List(1,2,3).traverseU(sum)

il ressemble à (carte et agrégat):

List(1,2,3).map(sum).reduceLeft(_ + _)

Je pense que c'est plus que cela pour traverseU, je me demande juste quelle est la différence entre ces 3 méthodes, il vaudrait mieux que j'aie un exemple de code pour montrer la différence

Merci d'avance

38
Xiaohe Dong

sequence est utilisé pour rassembler les effets applicatifs. Plus concrètement, il vous permet de "basculer" F[G[A]] Vers G[F[A]], À condition que G soit Applicative et F soit Traversable. Nous pouvons donc l'utiliser pour "rassembler" un tas d'effets Applicative (notez que tous les Monad sont 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")

traverse est équivalent à map puis sequence, vous pouvez donc l'utiliser lorsque vous avez une fonction qui renvoie un Applicative et que vous souhaitez simplement en obtenir un seul instance de votre Applicative plutôt qu'une liste d'entre eux:

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]]

traverseU est la même opération que traverse, juste avec les types exprimés différemment pour que le compilateur puisse les déduire plus facilement.

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"))

traverseM(f) est équivalent à traverse(f).map(_.join), où join est le nom scalaz pour flatten. Il est utile comme une sorte de "lifting flatMap":

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))
72
lmm