这个操作通常被称为序列化,并且在一些函数式语言的标准库中可用(例如Haskell)。在Scala中,您可以自己实现,也可以使用外部库,比如Scalaz。例如,假设我们有以下代码:
val xs: List[Either[String, Int]] = List(Right(1), Right(2))
val ys: List[Either[String, Int]] = List(Right(1), Left("1st!"), Left("2nd!"))
现在我们可以使用 Scalaz 7 编写如下代码:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> xs.sequenceU
res0: Either[String,List[Int]] = Right(List(1, 2))
scala> ys.sequenceU
res1: Either[String,List[Int]] = Left(1st!)
按照要求进行。
值得一提的是,这个操作只需要外部容器是可遍历的,并且内部容器是一个应用函子。Scalaz还提供了一个名为ValidationNEL
的类,它很像Either
,也符合这些要求,但在ValidationNEL
列表上使用sequence
会收集多个错误而不是停在第一个:
val zs: List[ValidationNEL[String, Int]] =
List(1.successNel, "1st".failNel, "2nd".failNel)
现在我们得到:
scala> print(zs.sequenceU)
Failure(NonEmptyList(1st, 2nd))
您还可以在 Option
、Promise
等列表上使用 sequence
。
Right[String]
,另一半是各种异构的Left[Exception]
。你想将它们缩减为一个异常或字符串列表。如果输入中有十个不同的异常,应该选择哪一个异常呢? - Tomasz Nurkiewicz