[英]How to transform F[Either[A, B]] to Either[F[A], F[B]]
A little bit of background: There is a .separate
function in cats that allows me to get tuple (F[A], F[B])
out of F[Either[A, B]]
. 背景知识:猫中有一个
.separate
函数,它使我可以从F[Either[A, B]]
获取元组(F[A], F[B])
。 Given that, one can easily construct Either[F[A], F[B]]
- given we can check F
for emptiness (a monoid would do?). 鉴于此,可以很容易地构造
Either[F[A], F[B]]
-鉴于我们可以检查F
的空性(类人动物会这样做吗?)。 The code for list could look like this 列表的代码可能如下所示
val l: List[Either[_, _]] = ???
l.separate match {
case (Nil, rights) => Right(rights)
case (lefts, _) => Left(lefts)
}
But this seems like a more general concept but I am not quite sure what that is. 但这似乎是一个更笼统的概念,但我不确定那是什么。 It looks kinda similar to
.sequence
but our G
has two holes. 它看起来有点类似于
.sequence
但是我们的G
有两个孔。 That is, we want a transformation F[G[A, B]] -> G[F[A], F[B]]
. 也就是说,我们想要一个变换
F[G[A, B]] -> G[F[A], F[B]]
。
Do you happen to know if such concept exists or how to achieve this goal with cats without pattern matching / if statements / Either.cond
? 您是否偶然知道这种概念是否存在,或者如何通过不带
pattern matching / if statements / Either.cond
猫来实现该目标?
You might try it with a combination of Alternative
and Traverse
. 您可以结合使用
Alternative
和Traverse
来尝试。
This special case can be generalized from List
to an arbitrary F
: 这种特殊情况可以从
List
推广到任意F
:
def collectErrors[A, B](xs: List[Either[A, B]]): Either[List[A], List[B]] = {
xs.traverse(_.left.map(List(_)).toValidated).toEither
}
Here is a shopping list of stuff that we need to make it work: 这是我们需要使其工作的东西的购物清单:
List(_)
. List(_)
。 That's usually Applicative[F].pure(_)
(or _.pure[F]
), so we need Applicative
. Applicative[F].pure(_)
(或_.pure[F]
),因此我们需要Applicative
。 Monoid
on F[X]
so we can accumulate errors in the left part of Validated
. F[X]
上的Monoid
,以便可以在Validated
的左侧累积错误。 Fortunately, there is MonoidK[F[_]]
, which knows how to generate a Monoid[F[X]]
for any given X
MonoidK[F[_]]
,它知道如何为任何给定X
生成Monoid[F[X]]
F[_]
must be traversable so we can get from F[Validated[F[A], B]]
to Validated[F[A], F[B]]
, thus we need Traverse
. F[_]
必须是可遍历的,因此我们可以从F[Validated[F[A], B]]
到Validated[F[A], F[B]]
,因此我们需要Traverse
。 There is a trait Alternative
, which is a combination of Applicative
and MonoidK
. 有一个特质
Alternative
,它是Applicative
和MonoidK
的组合。 Putting it all together gives you: 将所有内容放在一起将为您提供:
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
}
This should now work for List
, Vector
, Chain
, etc. 现在,这应该适用于
List
, Vector
, Chain
等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.