Handle
Handle[F, E]
extends Raise
with the ability to also handle raised errors.
It adds the handleWith
function, which can be used to recover from errors and therefore allow continuing computations.
The handleWith
function has the following signature:
def handleWith[A](fa: F[A])(f: E => F[A]): F[A]
This function is fully equivalent to handleErrorWith
from cats.ApplicativeError
and in general Handle
is fully equivalent to cats.ApplicativeError
,
but is not a subtype of Applicative
and therefore doesn't cause any ambiguitites.
Let's look at an example of how to use this function:
import cats._
import cats.syntax.all._
import cats.mtl._
import cats.mtl.implicits._
def parseNumber[F[_]: Applicative](in: String)(implicit F: Raise[F, String]): F[Int] = {
// this function might raise an error
if (in.matches("-?[0-9]+")) in.toInt.pure[F]
else F.raise(show"'$in' could not be parsed as a number")
}
def notRecovered[F[_]: Applicative](implicit F: Raise[F, String]): F[Boolean] = {
parseNumber[F]("foo")
.map(n => if (n > 5) true else false)
}
def recovered[F[_]: Applicative](implicit F: Handle[F, String]): F[Boolean] = {
parseNumber[F]("foo")
.handle[String](_ => 0) // Recover from error with fallback value
.map(n => if (n > 5) true else false)
}
val err = notRecovered[Either[String, *]]
// err: Either[String, Boolean] = Left(
// value = "'foo' could not be parsed as a number"
// )
val result = recovered[Either[String, *]]
// result: Either[String, Boolean] = Right(value = false)