Authors: @evdokim and @jordancoll
This repository demonstrates how Union Types can be used for type-safe error handling.
The ErrorMonad[F[_, _]]
type class that expresses composition of error-prone operations.
The key difference here from a regular Monad
is the addition of a left side that represents an error type. These error types are summed on the left side when composing operations, providing the user a precise list of possible errors:
def [EA, EB, A, B](fa: F[EA, A]) flatMap(f: A => F[EB, B]): F[EA | EB, B]
Let's make french fries:
val pommes = for {
potato <- getPotato() //: Either[GetPotatoError, Potato]
pommes <- makePommes(potato) //: Either[MakePommesError, Pommes]
} yield pommes //: Either[GetPotatoError | MakePommesError, Pommes]
You can check out a more detailed example that uses an async context here. We supplied an implementation using com.twitter.util.Future
, but it can be easily swapped out for any other effect library (like cats-effect
).
Similar to ErrorMonad
, we defined the ErrorApplicative
type class that can express parallel composition:
def [EA, EB, A, B](fa: F[EA, A]) product(fb: F[EB, B]): F[EA | EB, (A, B)]
See an example that accumulates validation errors here.