What is a good way to transform an Either (both left and right)?

I want to convert an Either[String, String] to an Either[FooError, FooSuccess]. One way to do this is

//decodeSuccess function is not in my control. It is a function provided by a library
def decodeSuccess(strSucess: String): Either[AnotherError, FooSuccess] = ???

def fooFunction: Either[FooError, FooSuccess] = 
    val a: Either[String, String] = ???
    a match 
        case Left(strError) => Left(FooError(strError)): Either[FooError, FooSuccess]
        case Right(strSuccess) => decodeSuccess(strSuccess)
            case Left(anotherErrror) => Left(FooError(anotherError.toString)): Either[FooError, FooSuccess]
            case Right(s) => Right(s): Either[FooError, FooSuccess]

But this involves too much nesting. The reason I can’t use flatMap is because flatMap on Either does’t allow you to change the type of the Left because it is right biased. I feel that there should be a better way of doing this which I am probably not getting to right now.

I’d go with .flatMap(decodeSuccess(_).left.map.(_.toString)).left.map(FooError) here

There also is fold

1 Like

thanks, I think I like fold better:)

To expand on @martijnhoekstra solution, consider making the code more readable:

  val anyOrDecoded = for {
    str <- a()
    decoded <- decodeSuccess(str)
  } yield decoded
  
  anyOrDecoded.left.map(any => FooError(any.toString))

One liners could be extremely confusing, especially when they transform both right and left values in the same line.

2 Likes