如何将 Future 的 disjunction 转化为 disjunction 的 Future

How to transform disjunction of Future to Future of disjunction

我有一个方法的结果: val res: Future[Int] Xor Future[String] = getResult(x)

并想对其进行转换并将其用作 Future[Int Xor String]

我无法从 herding cats blog 推断出我的用例,我不确定 monad 转换器是否是这里的正确工具,也许是某种形式的 traverse?

来自 cats 的

Xor 代表任何分离。 Scalaz \/ 或 stdlib Either 也可以(尽管我更喜欢有偏见的析取)。

谢谢

Scalaz 有 Functor.counzip,但 scalaz.syntax.functor 中没有 counzip,所以我们需要直接在 Functor[Future] 上调用它:

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 也有一个 Cozip 类型 class,它给你相反的结果:F[A \/ B] => F[A] \/ F[B].

正如 sequence 允许您将 F[G[A]] 变成 G[F[A]]F 有一个 Traverse 实例并且 G 是applicative,如果 F 有一个 Bitraverse 实例(并且 G 是适用的),bisequence 可以让你把 F[G[A], G[B]] 变成 G[F[A, B]]

Cats 已经为 at least a couple of versions 提供了 Bitraverse 实现(我这里使用的是 0.6.0-M2),所以你可以这样写:

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 有点像 Scalaz 的 ZipCozip (在另一个答案中提到),但它更通用,因为可以为具有两个的任何类型构造函数定义实例类型参数(假设它具有适当的语义),而不仅仅是元组或析取。