Podemos reescribir la poligonal en términos de un Aplicativo. Nuestro acumulador del ejemplo anterior:
Future(List.empty[Int])
es equivalente a Applicative.pure:
import cats.Applicative
import cats.instances.future._ // for Applicative
import cats.syntax.applicative._ // for pure
List.empty[Int].pure[Future]
Nuestro combinador, que solía ser este:
def oldCombine(accum : Future[List[Int]],host: String): Future[List[Int]] = {
val uptime = getUptime(host)
for {
accum <- accum
uptime <- uptime
} yield accum :+ uptime
}
ahora es equivalente a Semigroupal.combine:
import cats.syntax.apply._ // for mapN
// Combining accumulator and hostname using an Applicative:
def newCombine(accum: Future[List[Int]], host: String): Future[List[Int]] =
(accum, getUptime(host)).mapN(_ :+ _)
Al sustituir estos fragmentos en la definición de poligonal, podemos generalizarla para que funcione con cualquier aplicativo:
def listTraverse[F[_]: Applicative, A, B] (list: List[A])(func: A => F[B]): F[List[B]] =
list.foldLeft(List.empty[B].pure[F]) { (accum, item) =>
(accum, func(item)).mapN(_ :+ _)
}
def listSequence[F[_]: Applicative, B] (list: List[F[B]]): F[List[B]] =
listTraverse(list)(identity)
Podemos usar listTraverse para volver a implementar nuestro ejemplo de tiempo de actividad:
val totalUptime = listTraverse(hostnames)(getUptime)
Await.result(totalUptime, 1.second)
// res5: List[Int] = List(1020, 960, 840)
o podemos usarlo con otros tipos de datos de Applicative.