2017-01-17 27 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}