Scala:将整个列表中的任何一个与每个元素中的任何一个结合起来
Scala: Combine Either per the whole List with Either per elements
我有一个 Either 列表,表示错误:
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
,我想将所有错误和 return 合并。
我在 [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
Return这个求理解的类型必须是:
Either[List[String], List[Int]]
正如@Luis 在评论中提到的那样,ValidatedNel
就是您要查找的内容:
import cats.data.{ Validated, ValidatedNel }
import cats.implicits._
type ErrorType = String
def combine(listWithEither: List[Either[ErrorType, Int]]):ValidatedNel[ErrorType, List[Int]] =
listWithEither.foldMap(e => Validated.fromEither(e).map(List(_)).toValidatedNel)
val l1 = List[Either[ErrorType, Int]](Right(1), Right(2), Right(3))
val l2 = List[Either[ErrorType, Int]](Left("Incorrect String"), Right(2), Left("Validation error"))
println(combine(l1))
// Displays Valid(List(1, 2, 3))
println(combine(l2))
// Displays Invalid(NonEmptyList(Incorrect String, Validation error))
您可以使用 .toEither
将最终的而不是转换回 Either
,但是 ValidatedNel
是一个更好的累积错误的结构,而 Either
更适合fail fast
错误。
正如评论中已经提到的,Either
有利于 fail-fast 行为。对于累积多个错误,您可能需要 Validated
之类的东西。此外:
- 列表是可遍历的(具有
Traverse
的实例)
- 已验证适用
Validated.fromEither
将 Either[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
我有一个 Either 列表,表示错误:
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
,我想将所有错误和 return 合并。
我在 [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
Return这个求理解的类型必须是:
Either[List[String], List[Int]]
正如@Luis 在评论中提到的那样,ValidatedNel
就是您要查找的内容:
import cats.data.{ Validated, ValidatedNel }
import cats.implicits._
type ErrorType = String
def combine(listWithEither: List[Either[ErrorType, Int]]):ValidatedNel[ErrorType, List[Int]] =
listWithEither.foldMap(e => Validated.fromEither(e).map(List(_)).toValidatedNel)
val l1 = List[Either[ErrorType, Int]](Right(1), Right(2), Right(3))
val l2 = List[Either[ErrorType, Int]](Left("Incorrect String"), Right(2), Left("Validation error"))
println(combine(l1))
// Displays Valid(List(1, 2, 3))
println(combine(l2))
// Displays Invalid(NonEmptyList(Incorrect String, Validation error))
您可以使用 .toEither
将最终的而不是转换回 Either
,但是 ValidatedNel
是一个更好的累积错误的结构,而 Either
更适合fail fast
错误。
正如评论中已经提到的,Either
有利于 fail-fast 行为。对于累积多个错误,您可能需要 Validated
之类的东西。此外:
- 列表是可遍历的(具有
Traverse
的实例) - 已验证适用
Validated.fromEither
将Either[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