2015-05-08 58 views
0

我有Eithers慣用Scala的方式來Eithers列表到左或右視列表內容

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

結果列表,我想Right如果一切都在名單是Right否則我想要一個Left。這聽起來像列表應該有偏見(例如,使用Try),但我們假設它不是或不應該。

生成的RightLeft的內容將始終保持不變(例如一個字符串,請參見打擊) - 只有Container纔會有所不同。例如。有了上面的列表,我們想從這個列表創建一個字符串,所以結果應該是Left,比如Left("Right(5) -> Left(abc) -> Right(42)")。如果我們有另一個Right(12)而不是Left("abc")它應該是Right("Right(5) -> Right(12) -> Right(42)")

我可以手動檢查是否有至少一個Left在列表中,分支的,如果創建一個LeftRight的結果,但我想知道:是否有更多的斯卡拉般的方式做到這一點?

+0

什麼空列表,是一個'Right' ? – Bergi

+0

@Bergi仍然可以算作'Right',只要所有其他值也是'Right',那麼輸出仍然應該是'Right'的'Right' – valenterry

回答

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)) 
0

EitherSENCE值錯誤在Haskell實際使用。 但斯卡拉Either的設計不允許它用作「Error Monad」。這是通過\/ type固定在scalaz library。你想基本上通過sequence擴展Traverse類型實現。 因此,與前綴代碼:

import scalaz._ 
import Scalaz._ 

,並得到你的結果一樣

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

甚至ONELINE類型鑽營:

val mlist = (list map \/.fromEither).sequence[({type E[A] = String \/ A})#E, Int]