Nuestros métodos listTraverse y listSequence funcionan con cualquier tipo de Aplicativo, pero solo funcionan con un tipo de secuencia: List. Podemos generalizar sobre diferentes tipos de secuencias utilizando una type class, lo que nos lleva a Cats' Traverse. Aquí está la definición abreviada:
package cats
trait Traverse[F[_]] {
def traverse[G[_]: Applicative, A, B] (inputs: F[A])(func: A => G[B]): G[F[B]]
def sequence[G[_]: Applicative, B] (inputs: F[G[B]]): G[F[B]] = traverse(inputs)(identity)
}
Cats proporciona instancias de Poligonal para List, Vector, Stream, Option, Either y una variedad de otros tipos. Podemos invocar instancias como de costumbre usando Traverse.apply y usar los métodos poligonal y de secuencia como se describe en la sección anterior:
import cats.Traverse
import cats.instances.future._ // for Applicative
import cats.instances.list._
// for Traverse
val totalUptime: Future[List[Int]] = Traverse[List].traverse(hostnames)(getUptime)
Await.result(totalUptime, 1.second)
// res0: List[Int] = List(1020, 960, 840)
val numbers = List(Future(1), Future(2), Future(3))
val numbers2: Future[List[Int]] = Traverse[List].sequence(numbers)
Await.result(numbers2, 1.second)
// res1: List[Int] = List(1, 2, 3)
También hay versiones sintácticas de los métodos, importadas a través de cats.syntax.traverse:
import cats.syntax.traverse._ // for sequence and traverse
Await.result(hostnames.traverse(getUptime), 1.second)
// res2: List[Int] = List(1020, 960, 840)
Await.result(numbers.sequence, 1.second)
// res3: List[Int] = List(1, 2, 3)
Como puede ver, ¡es mucho más compacto y legible que el código foldLeft con el que comenzamos al principio!