Converting an Either to an IO

When using http4s, I came across a scenario where I need to convert an Either to an IO.

case GET -> root / start / end / "overall" =>
 for {
  s <-  FooAdt.fromString(start)
  e <- FooAdt.fromString(end)
 things <- thingsRepo.get(s, e)
} yield 
   Ok(things.asJson)

The above code will not compiler because here FooAdt.fromString returns an Either[Error, MyAdt] and thingsRepo.get returns an IO and that is also what the return container of the route is expected to be (IO).

What would be the idiomatic way of approaching the problem here?

Is Error a Throwable? In that case you can simply call IO.fromEither.

IO.fromEither(FooAdt.fromString(start))

Or alteratively

import cats.implicits._

FooAdt.fromString(start).liftTo[IO]

If it isn’t, then the easiest thing to do is probably converting Error to a Throwable.

e.g.

case class ThrowableError(error: Error) extends Exception

FooAdt.fromString(start).fold(ThrowableError andThen IO.raiseError, IO.pure)

// or

import cats.implicits._

FooAdt.fromString(start).leftMap(ThrowableError).liftTo[IO]
2 Likes

Error is not a throwable :frowning: But yeah I think I can use your solution of converting it to a Throwable.

If you mean java.lang.Error, that is a java.lang.Throwable. However, Future or 'Tryonly catch suchThrowables that are [Nonfatal`](https://www.scala-lang.org/api/2.13.3/scala/util/control/NonFatal$.html).

There are usually three approaches to modeling errors in IO.

  • User managed errors: IO[Either[E, A]
  • System managed errors: IO[A], where the errors are always Throwables.
  • Errors are just other values: IO[ADT] where you have your own ADT of all posible results, some of the branches of the ADT are errors.