问题
I have the result of a method:
val res: Future[Int] Xor Future[String] = getResult(x)
and would like to transform it and use it as Future[Int Xor String]
I could not extrapolate my use case from the herding cats blog and am not sure whether a monad transformer would be the right tool here, perhaps rather some form of traverse
?
Xor
from cats stands in for any disjunction. Scalaz \/
or stdlib Either
would be fine as well (though I would prefer a biased disjunction).
Thank you
回答1:
Just as sequence
allows you to turn a F[G[A]]
into a G[F[A]]
when F
has a Traverse
instance and G
is applicative, bisequence
lets you turn a F[G[A], G[B]]
into a G[F[A, B]]
if F
has a Bitraverse
instance (and G
is applicative).
Cats has provided a Bitraverse
implementation for at least a couple of versions (I'm using 0.6.0-M2 here), so you can just write this:
import cats.data.Xor, cats.std.future._, cats.syntax.bitraverse._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def flip[A, B](x: Xor[Future[A], Future[B]]): Future[Xor[A, B]] = x.bisequence
Bitraverse
is a little like Scalaz's Zip
or Cozip
(mentioned in the other answer), but it's more generic in that instances can be defined for any type constructor with two type arguments (assuming it has the appropriate semantics), not just tuples or disjunction.
回答2:
Scalaz has Functor.counzip
, but there is no counzip
in scalaz.syntax.functor
so we need to call it on Functor[Future]
directly :
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz.std.scalaFuture._
import scalaz.{\/, Functor}
val disj: Future[Int] \/ Future[String] = \/.right(Future.successful("foo"))
Functor[Future].counzip(disj)
// Future[Int \/ String] : Success(\/-(foo))
Scalaz also has a Cozip
type class which gives you the inverse : F[A \/ B] => F[A] \/ F[B]
.
来源:https://stackoverflow.com/questions/37327257/how-to-transform-disjunction-of-future-to-future-of-disjunction