我有一个任何一个列表,它代表错误:

type ErrorType = List[String]
type FailFast[A] = Either[ErrorType, A]

import cats.syntax.either._
val l = List(1.asRight[ErrorType], 5.asRight[ErrorType])

如果所有这些都正确,我想获得 [A] 的列表,在这种情况下 - List[Int]
如果留下任何 Either,我想合并所有错误并返回它。

我在 [ How to reduce a Seq[Either[A,B]] to a Either[A,Seq[B]] 找到了一个类似的主题

但那是很久以前的事了。例如,其中一个答案提供使用 partitionMap ,我目前找不到。可能有更好、更优雅的解决方案。使用 scala-cats 的例子会很棒。

我想如何使用它:
for {
  listWithEihers <- someFunction
  //if this list contains one or more errors, return Left[List[String]]
  //if everything is fine, convert it to:
  correctItems <- //returns list of List[Int] as right
} yield correctItems

这个 for-comprehension 的返回类型必须是:
Either[List[String], List[Int]]

最佳答案

正如评论中已经提到的, Either 有利于快速失败行为。为了累积多个错误,您可能需要类似 Validated 的东西。而且:

  • 列表是可遍历的(有 Traverse 的实例)
  • 验证是适用的
  • Validated.fromEitherEither[List[String], X] 映射到 Validated[List[String], X] ,这正是您在 traverse 中需要的功能。

  • 因此,您可以尝试:
  • l.traverse(Validated.fromEither) 如果你对 Validated 没问题
  • l.traverse(Validated.fromEither).toEither 如果你真的想要一个 Either 最后。

  • 所有导入的完整示例:
    import cats.data.Validated
    import cats.syntax.validated._
    import cats.syntax.either._
    import cats.syntax.traverse._
    import cats.instances.list._
    import cats.Traverse
    import scala.util.Either
    
    type ErrorType = List[String]
    type FailFast[A] = Either[ErrorType, A]
    val l: List[Either[ErrorType, Int]] = List(1.asRight[ErrorType], 5.asRight[ErrorType])
    
    // solution if you want to keep a `Validated`
    val validatedList: Validated[ErrorType, List[Int]] =
      l.traverse(Validated.fromEither)
    
    // solution if you want to transform it back to `Either`
    val eitherList: Either[ErrorType, List[Int]] =
      l.traverse(Validated.fromEither).toEither
    

    关于Scala:将整个列表的任一与每个元素的任一组合,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56258434/

    10-12 02:51