Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cats Seq[Xor[A,B]] => Xor[A, Seq[B]]

I have a sequence of Errors or Views (Seq[Xor[Error,View]])

I want to map this to an Xor of the first error (if any) or a Sequence of Views (Xor[Error, Seq[View]]) or possibly simply (Xor[Seq[Error],Seq[View])

How can I do this?

like image 422
Ben Flowers Avatar asked Dec 18 '22 12:12

Ben Flowers


2 Answers

You can use sequenceU provided by the bitraverse syntax, similar to as you would do with scalaz. It doesn't seem like the proper type classes exist for Seq though, but you can use List.

import cats._, data._, implicits._, syntax.bitraverse._

case class Error(msg: String)

case class View(content: String)

val errors: List[Xor[Error, View]] = List(
  Xor.Right(View("abc")), Xor.Left(Error("error!")), 
  Xor.Right(View("xyz"))
)

val successes: List[Xor[Error, View]] = List(
  Xor.Right(View("abc")),
  Xor.Right(View("xyz"))
)

scala> errors.sequenceU
res1: cats.data.Xor[Error,List[View]] = Left(Error(error!))

scala> successes.sequenceU
res2: cats.data.Xor[Error,List[View]] = Right(List(View(abc), View(xyz)))
like image 94
Michael Zajac Avatar answered Dec 26 '22 21:12

Michael Zajac


In the most recent version of Cats Xor is removed and now the standard Scala Either data type is used.

Michael Zajac showed correctly that you can use sequence or sequenceU (which is actually defined on Traverse not Bitraverse) to get an Either[Error, List[View]].

import cats.implicits._

val xs: List[Either[Error, View]] = ???

val errorOrViews: Either[Error, List[View]] = xs.sequenceU

You might want to look at traverse (which is like a map and a sequence), which you can use most of the time instead of sequence.

If you want all failing errors, you cannot use Either, but you can use Validated (or ValidatedNel, which is just a type alias for Validated[NonEmptyList[A], B].

import cats.data.{NonEmptyList, ValidatedNel}

val errorsOrViews: ValidatedNel[Error, List[View]] = xs.traverseU(_.toValidatedNel)

val errorsOrViews2: Either[NonEmptyList[Error], List[View]] = errorsOrViews.toEither

You could also get the errors and the views by using MonadCombine.separate :

val errorsAndViews: (List[Error], List[View]) = xs.separate

You can find more examples and information on Either and Validated on the Cats website.

like image 39
Peter Neyens Avatar answered Dec 26 '22 23:12

Peter Neyens