CanCatch - Cats

CanCatch

CanCatch lets you catch NonFatal Throwable in the F[A] and turned it into F[Either[Throwable, A]]. It takes a function from Throwable to your own error type, yet it can handle only NonFatal ones as already mentioned.

trait CanCatch[F[_]] {
def catchNonFatal[A, B](fb: => F[B])(f: Throwable => A): F[Either[A, B]]
def catchNonFatalEither[A, B](fab: => F[Either[A, B]])(f: Throwable => A): F[Either[A, B]]
def catchNonFatalEitherT[A, B](fab: => EitherT[F, A, B])(f: Throwable => A): EitherT[F, A, B]
}

CanCatch.catchNonFatal

CanCatch[F].catchNonFatal[A, B] lets you catch NonFatal Throwable from F[B] and returns F[Either[A, B]].

How to Use

import cats.effect._
import effectie.cats._
val fa = CanCatch[IO].catchNonFatal(
IO(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: IO[Either[Throwable, Nothing]] = Map(
// Bind(Delay(<function0>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@3609cee0,
// 0
// )
fa.unsafeRunSync()
// res1: Either[Throwable, Nothing] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(101), <function1>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@2a0bf42a,
// 0
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(202)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202

Unhappy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-101)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(-1), <function1>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@29067e96,
// 0
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]

CanCatch.catchNonFatalEither

CanCatch[F].catchNonFatalEither[A, B] lets you catch NonFatal Throwable from F[Either[A, B]] and returns F[Either[A, B]].

How to Use

import cats.effect._
import effectie.cats._
val fa = CanCatch[IO].catchNonFatalEither(
IO((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int])
)(identity)
// fa: IO[Either[Throwable, Int]] = Map(
// Bind(Delay(<function0>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@259604b6,
// 1
// )
fa.unsafeRunSync()
// res19: Either[Throwable, Int] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(Right(100)), <function1>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@2f8c42bf,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(Right(-100)), <function1>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@6cbaed90,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])

CanCatch.catchNonFatalEitherT

CanCatch[F].catchNonFatalEitherT[A, B] lets you catch NonFatal Throwable from EitherT[F, A, B] and returns EitherT[F, A, B].

How to Use

import cats.data.EitherT
import cats.effect._
import effectie.cats._
val fa = CanCatch[IO].catchNonFatalEitherT(
EitherT(IO((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int]))
)(identity)
// fa: EitherT[IO, Throwable, Int] = EitherT(
// Map(
// Bind(Delay(<function0>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@42da4977,
// 1
// )
// )
fa.value.unsafeRunSync()
// res37: Either[Throwable, Int] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.data.EitherT
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(
// Bind(
// Pure(Right(100)),
// cats.data.EitherT$$Lambda$10986/0x0000000103266040@6c389ef3
// ),
// <function1>
// ),
// scala.Function1$$Lambda$10983/0x0000000103264040@1c6a2674,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example

import cats._
import cats.data.EitherT
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.EitherTSupport._
import effectie.cats.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[IO](-1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(
// Bind(
// Pure(Right(-100)),
// cats.data.EitherT$$Lambda$10986/0x0000000103266040@4752ae11
// ),
// <function1>
// ),
// scala.Function1$$Lambda$10983/0x0000000103264040@7e3983c5,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])

Catching

Catching.catchNonFatal provides a convenient way to use CanCatch to catch NonFatal Throwable in the F[A] and turned it into F[Either[Throwable, A]]. Just like CanCatch, it takes a function from Throwable to your own error type, yet it can handle only NonFatal ones as already mentioned.

Catching.catchNonFatal

catchNonFatal lets you catch NonFatal Throwable from F[B] and returns F[Either[A, B]].

How to Use

import cats.effect._
import effectie.cats.Catching._
val fa = catchNonFatal(
IO(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: IO[Either[Throwable, Nothing]] = Map(
// Bind(Delay(<function0>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@404f32f8,
// 0
// )
fa.unsafeRunSync()
// res55: Either[Throwable, Nothing] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(101), <function1>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@6967f0be,
// 0
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(202)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202

Unhappy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-101)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(-1), <function1>), <function1>),
// effectie.cats.CanCatch$$anon$1$$Lambda$10963/0x00000001031d9040@5419f510,
// 0
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]

Catching.catchNonFatalEither

Catching.catchNonFatalEither provides a convenient way to use CanCatch to catch NonFatal Throwable from F[Either[A, B]] and returns F[Either[A, B]].

How to Use

import cats.effect._
import effectie.cats.Catching._
val fa = catchNonFatalEither(
IO((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int])
)(identity)
// fa: IO[Either[Throwable, Int]] = Map(
// Bind(Delay(<function0>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@72b728dd,
// 1
// )
fa.unsafeRunSync()
// res73: Either[Throwable, Int] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(Right(100)), <function1>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@7fd4bf35,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example

import cats._
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(Bind(Pure(Right(-100)), <function1>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@7f263a28,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])

Catching.catchNonFatalEitherT

Catching.catchNonFatalEitherT provides a convenient way to use CanCatch to catch NonFatal Throwable from EitherT[F, A, B] and returns EitherT[F, A, B].

How to Use

import cats.data.EitherT
import cats.effect._
import effectie.cats.Catching._
val fa = catchNonFatalEitherT[IO](
EitherT(IO((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int]))
)(identity)
// fa: EitherT[IO, Throwable, Int] = EitherT(
// Map(
// Bind(Delay(<function0>), <function1>),
// scala.Function1$$Lambda$10983/0x0000000103264040@1fe6ecba,
// 1
// )
// )
fa.value.unsafeRunSync()
// res91: Either[Throwable, Int] = Left(
// java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example

import cats._
import cats.implicits._
import cats.data.EitherT
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
import effectie.cats.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[IO](1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(
// Bind(
// Pure(Right(100)),
// cats.data.EitherT$$Lambda$10986/0x0000000103266040@7a6fe75e
// ),
// <function1>
// ),
// scala.Function1$$Lambda$10983/0x0000000103264040@3ebb10f8,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Right(200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example

import cats._
import cats.data.EitherT
import cats.implicits._
import cats.effect._
import effectie.cats._
import effectie.cats.Effectful._
import effectie.cats.Catching._
import effectie.cats.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[IO](-1)
// fa: IO[Either[MyError, Int]] = Map(
// Bind(
// Bind(
// Pure(Right(-100)),
// cats.data.EitherT$$Lambda$10986/0x0000000103266040@70be05f7
// ),
// <function1>
// ),
// scala.Function1$$Lambda$10983/0x0000000103264040@6968d6e9,
// 1
// )
val result = fa.unsafeRunSync()
// result: Either[MyError, Int] = Left(
// NonFatalThrowable(
// java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])