Translate

sábado, 4 de febrero de 2023

Foldable y Traverse parte 7

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!