FlatMap代码背后的魔力是什么?

时间:2018-07-06 06:58:33

标签: scala list flatmap

我正在学习Scala,并在下面的代码中使用flatMap (摘自filter with flatmap or collect

我有

list flatMap {
    case st: String => Some(st)
    case _ => None
}

它可以在List[Any]上工作并产生List[String]

scala> List(1, "A") flatMap {
     | case st: String => Some(st)
     | case _  => None
     | }
res21: List[String] = List(A)

现在,我对这里的types感到困惑。如我所想,flatMap适用于某些monad,它是对M[M[A]] -> M[A]的转换。

下面的代码很容易理解,

def flatten(ls: List[Any]): List[Any] = ls flatMap {
    case ms: List[_] => flatten(ms)
    case e => List(e)
}

由于两种情况都返回一个List[Any],它仍然是ls: List[Any]的同一类型。

但是为什么Some[String]的{​​{1}}中的NoneflatMap是可接受的?

此外,似乎List[Any]被完全忽略了,而不是被视为一个严重的值?我当时在想可能有一些压缩步骤来消除这些值,例如:

None

有人可以解释这些吗?谢谢!!!

2 个答案:

答案 0 :(得分:4)

  

我认为,flatMap在某些monad上运行,这是从M [M [A]]-> M [A]的转换。

Scala flatMap比较笼统(有些人不喜欢)。

如果您查看documentation,传递给List#flatMap的函数就返回GenTraversableOnce[SomeType]而不是List[SomeType]就足够了。即使Option没有扩展GenTraversableOnce,它们之间也有一个implicit conversion会在此处应用。

  

此外,似乎完全忽略了None而是将其视为一个严肃的值?

None对应于一个空集合,Some(x)对应于一个单元素集合。所以你有

Some(1) ++ Some(2) ++ None ++ Some(3) ==
List(1) ++ List(2) ++ List() ++ List(3) ==
List(1,2,3)

或者,按照您的说法,您没有[1,2,3,,,4](没有意义),但是没有[[1],[2],[3],[],[],[4]]

答案 1 :(得分:1)

flatMap不限于相同类型的嵌套集合。传递给flatMap的函数返回的值可以是任何集合类型。 flatMap将采用该集合中的每个元素,并将其附加到结果集合中。 Option[T]的工作方式类似于0或1个元素的集合,因此flatMap的工作方式与ListVectorArray或其他集合一样。

但是,在这种特定情况下,您实际上会使用collect而不是flatMap

list.collect{ case s: String => s }