Los funtores y las mónadas nos permiten secuenciar operaciones usando map y flatMap. Si bien los funtores y las mónadas son abstracciones inmensamente útiles, hay ciertos tipos de flujo de programa que no pueden representar.
Un ejemplo de ello es la validación de formularios. Cuando validamos un formulario, queremos devolver todos los errores al usuario, no detenernos en el primer error que encontremos. Si modelamos esto con una mónada como Either, fallamos rápidamente y perdemos errores. Por ejemplo, el siguiente código falla en la primera llamada a parseInt y no avanza más:
import cats.syntax.either._ // for catchOnly
def parseInt(str: String): Either[String, Int] = Either.catchOnly[NumberFormatException](str.toInt).
leftMap(_ => s"Couldn't read $str")
for {
a <- parseInt("a")
b <- parseInt("b")
c <- parseInt("c")
} yield (a + b + c)
// res0: Either[String, Int] = Left("Couldn't read a")
Otro ejemplo es la evaluación concurrente de Futures. Si tenemos varias tareas independientes de larga duración, tiene sentido ejecutarlas simultáneamente. Sin embargo, la comprensión monádica solo nos permite ejecutarlos en secuencia. map y flatMap no son del todo capaces de capturar lo que queremos porque suponen que cada cálculo depende del anterior:
// context2 is dependent on value1:
context1.flatMap(value1 => context2)
Las llamadas a parseInt y Future.apply anteriores son independientes entre sí, pero map y flatMap no pueden aprovechar esto. Necesitamos una construcción más débil, una que no garantice la secuenciación, para lograr el resultado que queremos. Veremos tres clases de tipos que soportan este patrón:
- Semigroupal abarca la noción de componer pares de contextos. Cats proporciona un módulo cats.syntax.apply que utiliza Semigroupal y Functor para permitir a los usuarios secuenciar funciones con múltiples argumentos.
- Parallel convierte tipos con una instancia de Monad en un tipo relacionado con una instancia de Semigroupal.
- Applicative extiende Semigroupal y Functor. Proporciona una forma de aplicar funciones a parámetros dentro de un contexto.E
Applicatives a menudo se formulan en términos de aplicación de funciones, en lugar de la formulación semigrupal que se enfatiza en Cats. Esta formulación alternativa proporciona un enlace a otras bibliotecas y lenguajes como Scalaz y Haskell. Veremos las diferentes formulaciones de Applicative, así como las relaciones entre Semigroupal, Functor, Applicative y Monad.