domingo, 27 de noviembre de 2022

Semigroupal, Parallel y Applicative parte 2

cats.Semigroupal es una clase de tipos que nos permite combinar contextos. Si tenemos dos objetos de tipo F[A] y F[B], un Semigroupal[F] nos permite combinarlos para formar un F[(A, B)]. Su definición en Cats es:


trait Semigroupal[F[_]] {

    def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]

}


Como comentamos en un post anterior, los parámetros fa y fb son independientes entre sí: podemos calcularlos en cualquier orden antes de pasarlos al producto. Esto contrasta con flatMap, que impone un orden estricto en sus parámetros. Esto nos da más libertad cuando definimos instancias de Semigroupal que cuando definimos Monads. 

Mientras que Semigroup nos permite unir valores, Semigroupal nos permite unir contextos. Juntemos algunas Opciones como ejemplo:

import cats.Semigroupal

import cats.instances.option._ // for Semigroupal

Semigroupal[Option].product(Some(123), Some("abc"))

// res1: Option[(Int, String)] = Some((123, "abc"))


Si ambos parámetros son instancias de Some, terminamos con una tupla de los valores dentro. Si alguno de los parámetros se evalúa como None, el resultado completo es None:


Semigroupal[Option].product(None, Some("abc"))

// res2: Option[Tuple2[Nothing, String]] = None

Semigroupal[Option].product(Some(123), None)

// res3: Option[Tuple2[Int, Nothing]] = None


El objeto complementario de Semigroupal define un conjunto de métodos además del producto. Por ejemplo, los métodos tuple2 a tuple22 generalizan el producto a diferentes aridades:


import cats.instances.option._ // for Semigroupal

Semigroupal.tuple3(Option(1), Option(2), Option(3))

// res4: Option[(Int, Int, Int)] = Some((1, 2, 3))

Semigroupal.tuple3(Option(1), Option(2), Option.empty[Int])

// res5: Option[(Int, Int, Int)] = None


Los métodos map2 a map22 aplican una función especificada por el usuario a los valores dentro de 2 a 22 contextos:


Semigroupal.map3(Option(1), Option(2), Option(3))(_ + _ + _)

// res6: Option[Int] = Some(6)

Semigroupal.map2(Option(1), Option.empty[Int])(_ + _)

// res7: Option[Int] = None


También existen métodos contramap2 a contramap22 e imap2 a imap22, que requieren instancias de Contravariant e Invariant respectivamente.

Solo hay una ley para Semigroupal: el método del producto debe ser asociativo.


product(a, product(b, c)) == product(product(a, b), c)



No hay comentarios.:

Publicar un comentario