I just found a MonadError code snippet that uses Either
like the following
import cats.MonadError
import cats.instances.either._ // for MonadError
type ErrorOr[A] = Either[String, A]
val monadError = MonadError[ErrorOr, String]
val success = monadError.pure(42)
println(success)
// success: ErrorOr[Int] = Right(42)
val failure = monadError.raiseError("Badness")
println(failure)
// failure: ErrorOr[Nothing] = Left("Badness")
The above code compiles and gives expected result.
Then I tried to do the same for Try
import cats.MonadError
import cats.instances.try_._
type TryOr[A] = Try[A]
val monadError = MonadError[TryOr, String]
val success = monadError.pure(42)
println(success)
val failure = monadError.raiseError("Badness")
println(failure)
this code doesn't compile. it says no implicit found for parameter F:MonadError[TryOr, String]
I went to the definition of MonadError and found following.
object MonadError {
def apply[F[_], E](implicit F: MonadError[F, E]): MonadError[F, E] = F
}
But didn't understand why it worked for Either
but not working for Try
. Why we need additional implicit even after import cats.instances.try_._
Can you help understand what is happening in the background ?
CodePudding user response:
With Try
you should use only Throwable
as an error type. This is a limitation of the Try
design. MonadError[Throwable, A]
. You can check Try
instances cats.instances.TryInstances
. There is only MonadThrow
instance.
type TryOr[A] = Try[A]
val monadError = MonadThrow[TryOr]
val success = monadError.pure(42)
println(success)
val failure = monadError.raiseError(new Exception("Badness"))
println(failure)