package com.zibaldone.cats
package ch_03
import cats.{Monad, Semigroupal}
trait `semigroupal`[F[_]]:
// Semigroupal doesn't have to be defined in terms of Monad, sometimes that would be illegal.
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
import cats.syntax.flatMap.*
import cats.syntax.functor.*
// ex. implement semigroupal with monad
def productWithMonads[F[_]: Monad, A, B](fa: F[A], fb: F[B]): F[(A, B)] =
for
a <- fa
b <- fb
yield (a, b)
// Semigroupal[ErrorOrEither] === Monad[ErrorOrEither]
import cats.instances.either.*
type ErrorOrEither[A] = Either[List[String], A]
// because of the short-circuiting in flatMap, 'c' will never be accumulated
val eitherSemigroupal = Semigroupal[ErrorOrEither].product(
fa = Left("a" :: "b" :: Nil),
fb = Left("c" :: Nil)
)
import cats.data.Validated
type ErrorOrValidated[A] = Validated[List[String], A]
// Semigroupal[ErrorOrValidated] provides a more flexible definition of product `without` using flatMap
val validatedSemigroupal = Semigroupal[ErrorOrValidated].product(
fa = Validated.invalid("a" :: "b" :: Nil),
fb = Validated.invalid("c" :: Nil)
)
// ex. Semigroupal[List] that zips
given Semigroupal[List] = new Semigroupal[List]:
override def product[A, B](fa: List[A], fb: List[B]): List[(A, B)] = fa.zip(fb)