Skip to content

Instantly share code, notes, and snippets.

@programaker
Last active November 16, 2021 18:58
Show Gist options
  • Save programaker/34f15f6ba4a2faaa1bfcece06787fa04 to your computer and use it in GitHub Desktop.
Save programaker/34f15f6ba4a2faaa1bfcece06787fa04 to your computer and use it in GitHub Desktop.
Dealing with errors using Alternative and Bitraverse typeclasses
import cats.effect.IO
def doThings(things: List[Int]): IO[List[Either[Throwable, String]]] = {
import cats.syntax.traverse._
things.traverse { i =>
if (i % 2 == 0)
IO(Right(s"$i = yay!"))
else
IO(Left(new Exception(s"$i = oh no!")))
}
}
def logThings(things: List[Either[Throwable, String]]): IO[Unit] = {
import cats.syntax.alternative._
import cats.syntax.bitraverse._
def logIfNonEmpty[A](log: List[A] => IO[Unit])(la: List[A]): IO[Unit] =
if (la.nonEmpty)
log(la)
else
IO.unit
things
// `Alternative.separateFoldable`:
// separates the List[Either[Throwable, String]] into (List[Throwable], List[String])
//
// `separateFoldable` is better than `separate` when `F` has also a
// Foldable instance (like List here), because it's a single-pass operation.
//
// `separate` is a 2-pass operation.
.separateFoldable
//
// `Bitraverse.bitraverse`:
// It's like `traverse`, but for a type constructor with 2 parameters - `F[_, _]`
// applies an effectful function (an `IO.println` log in this case) to each
// element of the resulting Tuple2 - one for _1 (errors) and another for _2 (successes)
.bitraverse(
logIfNonEmpty(errors => IO.println(s"[ERROR] thing errors: $errors")),
logIfNonEmpty(things => IO.println(s"[INFO] new things: $things"))
) *> IO.unit
}
///
val f = (doThings _).andThen(_.flatMap(logThings))
val program =
IO.println("===") *>
// mixed errors and infos
f(List(1, 2, 3, 4, 5, 6)) *>
IO.println("===") *>
// only infos
f(List(2, 4, 6, 8)) *>
IO.println("===") *>
// only errors
f(List(1, 3, 5, 7)) *>
IO.println("===")
import cats.effect.unsafe.implicits.global
program.unsafeRunSync()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment