5

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

val data = NonEmptyList[Either[Error, User]]

to

val target: Either[Error, NonEmptyList[User]] = howToConvert(data)
Freewind
  • 193,756
  • 157
  • 432
  • 708
  • 1
    I think your task is underspecified. What if you had several errors? How they should be aggregated into a single error? Moreover if you have some non-failed `User`s and some `Error`s, what you expect to get? Some `Error` or the list of successful `User`s? – SergGr Jan 14 '18 at 14:13
  • @SergGr Thanks for your questions. If there are several errors, I just want the final result to have the first one – Freewind Jan 14 '18 at 14:47
  • And if there are both `Error`s and valid `User`s? – SergGr Jan 14 '18 at 15:05
  • @SergGr, then it will be a `Left(error)` – Freewind Jan 14 '18 at 17:31

1 Answers1

5

Usually when you want to turn the type constructors inside out you are probably looking for sequence. If you have -Ypartial-unification turned on in Scala >= 2.11.9 you can just let the compiler infer everything:

data.sequence

Otherwise:

type EitherError[A] = Either[Error, A]
data.sequence[EitherError, User]

Or if you have the type lambda plugin:

data.sequence[Either[Error, ?], User]

Or if you don't have the plugin, but you dislike type aliases:

data.sequence[({type L[A] = Either[Error, A]})#L, User]

It will do the expected thing of either returning the first error, or all users if there is no error. If we pretend users are ints and errors are strings:

scala> import cats.data.NonEmptyList, cats.implicits._
import cats.data.NonEmptyList
import cats.implicits._

scala> val data: NonEmptyList[Either[Error, User]] = NonEmptyList.of(Right(2), Left("error1"), Right(4))
data: cats.data.NonEmptyList[Either[Error,User]] = NonEmptyList(Right(2), Left(error1), Right(4))

scala> data.sequence
res4: Either[Error,cats.data.NonEmptyList[User]] = Left(error1)
Jasper-M
  • 14,966
  • 2
  • 26
  • 37