Last active
November 16, 2021 18:58
-
-
Save programaker/34f15f6ba4a2faaa1bfcece06787fa04 to your computer and use it in GitHub Desktop.
Dealing with errors using Alternative and Bitraverse typeclasses
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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