2017-01-17 29 views
3

Either是正確的偏向斯卡拉2.12,它允許它在沒有投影的情況下用於for/yield塊,就像Option一樣。但顯然這與flatMap一起使用時的行爲不如Option在Scala中使用flatMap列表[任一]

object Main { 

    def main(args: Array[String]): Unit = { 

    val nums = List.range(1,10) 

    println(nums.flatMap(evenOption)) 
    println(nums.flatMap(evenEither)) // fails 

    } 

    def evenOption(x: Int): Option[Int]  = if (x % 2 == 0) Some(x) else None 
    def evenEither(x: Int): Either[String, Int] = if (x % 2 == 0) Right(x) else Left("not even") 

} 

我最小的範疇理論知識讓我覺得Either不是一個單子,所以這個不成?或者我怎麼能讓上面的例子工作?

+0

該問題可能與以下事實有關:或者不擴展TraversableOnce? – Mikel

回答

7

它與無論是否成爲單子無關。當您在某些數據結構上執行flatMap方法時,您傳入的函數必須返回該數據結構的一個實例。所以當你在一個選項上平面圖時,你的函數必須返回一個選項。如果你正在爲未來打平,你的功能必須返回一個未來。列表也是如此:列表上的平面映射必須返回列表本身。那麼爲什麼你的List.flatMap(Option)工作和List.flatMap(Either)沒有?因爲有一個從Option到Iterable的隱式轉換(Option.option2Iterable),並且該轉換髮生在您的示例中。對於任何一種數據類型都沒有這種轉換(除非你自己創建它)。

+0

for/yield如何進行平面映射?例如:'for {n < - nums; x < - evenEither(n)} yield n' – TomTom

+0

每個生成器('<-')將被轉換爲'flatMap'操作,最後的'yield'將被轉換爲'map'操作。有關更多詳細信息,請查看官方文檔:http://docs.scala-lang.org/tutorials/FAQ/yield.html。如果您還有其他問題,請隨時提問。 –

2

對於將List[Either[String,Int]]拼合成List[Int]沒有隱含的規則,所以您必須提供這樣做的手段。

nums.map(evenEither).flatten {case Right(e) => List(e) 
           case _ => List()} 

但是,這可以更直接地表達一點。

nums.collect{case x if evenEither(x).isRight => x}