Skip to content

Instantly share code, notes, and snippets.

@programaker
Created November 8, 2021 17:38
Show Gist options
  • Save programaker/0da5e378c0ed30bcaefbfa639b5281fb to your computer and use it in GitHub Desktop.
Save programaker/0da5e378c0ed30bcaefbfa639b5281fb to your computer and use it in GitHub Desktop.
The Align typeclass
import scala.util.Try
import cats.Functor
import cats.Align
import cats.data.Ior
type Decimal = Int
type Roman = String
def f[F[_]: Align: Functor](fi: F[Decimal], fs: F[Roman]): F[String] =
import cats.syntax.align.* // <- HERE
import cats.syntax.functor.*
// `align` is like a "zip on steroids"!
// It pairs 2 effects regardless whether they are symmetric or not
// i.e they have the same size, they are both defined, they are both successful, etc.
//
// The `Align` typeclass provides more interesting "zippers" like this.
// Check them out! https://typelevel.org/cats/api/cats/Align.html
fi.align(fs).map { ior =>
ior match
case Ior.Both(decimal, roman) => s"$decimal is $roman in Roman"
case Ior.Left(decimal) => s"$decimal has no Roman"
case Ior.Right(roman) => s"$roman has no Decimal"
}
///
val decimals1 = List(1, 2, 3, 0)
val romans1 = List("I", "II", "III")
val out1 = f(decimals1, romans1)
// List[String] = List(1 is I in Roman, 2 is II in Roman, 3 is III in Roman, 0 has no Roman)
val decimals2 = List(1, 2, 3)
val romans2 = List("I", "II", "III", "IV")
val out1a = f(decimals2, romans2)
// List[String] = List(1 is I in Roman, 2 is II in Roman, 3 is III in Roman, IV has no Decimal)
val out1b = f(List.empty, List.empty)
// List[String] = List()
///
import cats.syntax.option.*
val out2 = f(0.some, None)
// Option[String] = Some(1 is I in Roman)
val out2a = f(1.some, "I".some)
// Option[String] = Some(1 is I in Roman)
val out2b = f(None, "X".some)
// Option[String] = Some(X has no Decimal)
val out2c = f(None, None)
///
type Either_[A] = Either[String, A]
val out3 = f(Right(1), Left("ERROR"))
// Either[String, String] = Right(1 has no Roman)
val out3a = f[Either_](Right(1), Right("I"))
// Either[String, String] = Right(1 is I in Roman)
val out3b = f(Left("ERROR"), Right("X"))
// Either[String, String] = Right(X has no Decimal)
val out3c = f[Either_](Left("ERROR"), Left("ERROR"))
// Either[String, String] = Left(ERROR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment