5

I'm using cats, wonder how to turn a data with it.

From

val data = Either[Error, Option[Either[Error, Account]]]

to

val target: Either[Error, Option[Account]] = howToConvert(data)

If there is any Error happens, the result will be Left(error) with the first appeared error.

I can do it now with:

data match {
  case Left(e) => Left(e)
  case Right(Some(Right(y))) => Right(Some(y))
  case Right(Some(Left(e))) => Left(e)
  case Right(None) => Right(None)
}

But I'm looking for some easy way

dbc
  • 104,963
  • 20
  • 228
  • 340
Freewind
  • 193,756
  • 157
  • 432
  • 708

2 Answers2

7

The easiest way to do this is to sequence the inner Option, so that you get an Either[Error, Either[Error, Option[Account]]] and then flatten it. With cats syntax this is really easy:

import cats.implicits._

val target: Either[Error, Option[Account]] =
  data.flatMap(_.sequence)

To clarify, sequence turns a type constructor "inside out", meaning the inner Option[Either[Error, Account]] is turned into an Either[Error, Option[Account]].

Luka Jacobowitz
  • 22,795
  • 5
  • 39
  • 57
  • Nice, but what else needs to get imported? I am getting: ```polymorphic expression cannot be instantiated to expected type; [error] found : [G[_], A]G[Option[A]] [error] required: scala.util.Either[Error,Option[Account]] [error] val my: Either[Error, Option[Account]] = data.flatMap(_.sequence)``` – thesamet Jan 15 '18 at 16:40
  • 1
    Those are all the imports you need. You might need to enable `-Ypartial-unification` though. – Luka Jacobowitz Jan 15 '18 at 16:44
1

Here's an "easy" way that only assumes a right-biased Either (Scala 2.12), or cats' syntax

val target: Either[Error, Option[Account]] =
    data.flatMap(_.map(_.map(Some(_))).getOrElse(Right(None)))
thesamet
  • 6,382
  • 2
  • 31
  • 42