0

我有一份清单

val list: List[Either[String, Int]] = List(Right(5), Left("abc"), Right(42))

结果,我想要 a Rightif 列表中的所有内容都是 a Rightelse 我想要 a Left。这听起来像列表应该有偏见(例如使用Try代替),但让我们假设它不是或不应该是。

结果的内容RightorLeft将始终相同(例如,字符串,见吹) - 只有 Container 应该不同。例如,对于上面的列表,我们希望从该列表中创建一个字符串,因此结果应该是Leftlike Left("Right(5) -> Left(abc) -> Right(42)")。如果我们有另一个Right(12)而不是Left("abc")它应该是Right("Right(5) -> Right(12) -> Right(42)")

我可以手动检查列表中是否至少有一个Left,并使用 if 进行分支以创建 aLeft或 aRight作为结果,但我想知道:是否有更类似于 Scala 的方式来做到这一点?

4

2 回答 2

0

您可以使用foldLeft.

基本上在折叠功能中,您使用规则折叠

Right + Right => Right
SomethingElse => Left

在 Scala 代码中:

def string(a: Any, b: Any): String = if (a.toString.isEmpty)
   s"${b.toString}" else s"${a.toString} -> ${b.toString}"

def transform[T, U](list: List[Either[T, U]]) = 
  list.foldLeft[Either[String, String]](Right("")) {
    case (Right(a), bb @ Right(b)) => Right(string(a, bb))
    case (Right(a), bb) => Left(string(a, bb))
    case (Left(a), bb) => Left(string(a, bb))
  }

transform(List(Right(5), Left("abc"), Right(42)))
// prints Left(Right(5) -> Left(abc) -> Right(42))
transform(List(Right(5), Right("abc"), Right(42)))
// prints Right(Right(5) -> Right(abc) -> Right(42))
于 2015-05-10T21:07:23.047 回答
0

Either实际上用于 Haskell 中的错误。但是 scalaEither的设计不允许它用作“错误单子”。这是通过type在scalaz 库中修复的。你想通过类型扩展来实现的东西。所以在你的代码前加上:\/sequenceTraverse

import scalaz._
import Scalaz._

并得到你的结果

type Error[A] = String \/ A
val mlist = (list map \/.fromEither).sequence[Error, Int] 

甚至是单行类型的柯里化:

val mlist = (list map \/.fromEither).sequence[({type E[A] = String \/ A})#E, Int]
于 2015-05-22T09:07:18.387 回答