3
votes

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

2

2 Answers

10
votes

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.

3
votes

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].