如何将F [Either [A,B]]转换为Either [F [A],F [B]]

时间:2019-07-12 18:57:50

标签: scala scala-cats

背景知识:猫中有一个.separate函数,它使我可以从(F[A], F[B])中提取元组F[Either[A, B]]。鉴于此,我们可以轻松构造Either[F[A], F[B]]-假设我们可以检查F是否为空(一个类人动物会做什么?)。 list的代码可能看起来像这样

val l: List[Either[_, _]] = ???
l.separate match {
  case (Nil, rights) => Right(rights)
  case (lefts, _) => Left(lefts)
}

但是,这似乎是一个更笼统的概念,但我不确定那是什么。它看起来与.sequence类似,但我们的G有两个孔。也就是说,我们需要一个转换F[G[A, B]] -> G[F[A], F[B]]

您碰巧知道这种概念是否存在,或者如何在没有pattern matching / if statements / Either.cond的情况下养猫来实现这个目标?

1 个答案:

答案 0 :(得分:3)

您可以结合使用AlternativeTraverse进行尝试。

This special case可以从List推广到任意F

def collectErrors[A, B](xs: List[Either[A, B]]): Either[List[A], List[B]] = {
  xs.traverse(_.left.map(List(_)).toValidated).toEither
}

以下是我们要使其正常工作所需的购物清单:

  1. 我们需要某种List(_)的替代品。通常是Applicative[F].pure(_)(或_.pure[F]),因此我们需要Applicative
  2. 我们需要在Monoid上使用F[X],以便我们可以在Validated的左侧累积错误。幸运的是,这里有MonoidK[F[_]],它知道如何为任何给定的Monoid[F[X]]
  3. 生成X
  4. F[_]必须是可遍历的,这样我们才能从F[Validated[F[A], B]]Validated[F[A], F[B]],因此我们需要Traverse

有一个特征Alternative,它是ApplicativeMonoidK的组合。 全部放在一起可以给您:

  import scala.util.Either
  import cats._
  import cats.syntax.either._
  import cats.syntax.traverse._
  import cats.syntax.applicative._

  def collectErrors[F[_]: Alternative : Traverse, X, Y](xs: F[Either[X, Y]])
  : Either[F[X], F[Y]] = {
    implicit val mon = MonoidK[F].algebra[X]
    xs.traverse(_.left.map(_.pure[F]).toValidated).toEither
  }

这现在应该适用于ListVectorChain