简体   繁体   English

在Scala的List [Either]上使用flatMap

[英]Use flatMap on List[Either] in Scala

Either is right-biased ince Scala 2.12 which allows it to be used in for/yield blocks without projection just like Option . Either都在ince Scala 2.12中带有右偏,这使得它可以像Option一样用于投影/收益块中而无需投影。 But apparently this isn't enough to behave like Option when used with flatMap . 但这显然不足以与flatMap使用时像Option一样。

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

}

My minimal category theory knowledge makes me think that Either is not a monad and therefore this fails? 我的最小范畴理论知识使我认为, Either哪一个不是monad,因此失败了吗? Or how else can I make the example above work? 或者我还能如何使上面的示例起作用?

It has nothing to do with Either being or not being a monad. 与是否成为单子无关。 When you're executing flatMap method on some data structure, the function that you're passing into has to return an instance of that data structure. 在某些数据结构上执行flatMap方法时,要传递的函数必须返回该数据结构的实例。 So when you're flatmapping over an Option, your function has to return an Option. 因此,当您在Option上进行平面映射时,您的函数必须返回Option。 If you're flatmapping over a Future, your function has to return a Future. 如果您要映射Future,则您的函数必须返回Future。 The same goes with a List: flatmapping over a list has to return a List itself. List也是如此:对列表进行平面映射必须返回List本身。 So why does your List.flatMap(Option) work and List.flatMap(Either) doesn't? 那么,为什么您的List.flatMap(Option)起作用而List.flatMap(Either)不起作用? Because there's an implicit conversion from an Option to an Iterable ( Option.option2Iterable ), and that conversion took place in your example. 因为存在从Option到Iterable的隐式转换( Option.option2Iterable ),所以该转换发生在您的示例中。 There's no such conversion for the Either datatype (unless you create it yourself). Either数据类型没有这种转换(除非您自己创建)。

There are no implicit rules for flattening a List[Either[String,Int]] into a List[Int] , so you have to provide the means to do so. 没有将List[Either[String,Int]]List[Int]隐式规则,因此您必须提供这样做的方法。

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

But this can be expressed a little more directly. 但这可以更直接地表达出来。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM