这个 flatMap 代码背后的魔力是什么?

What's the magic behind this flatMap code?

我正在学习 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)
}

因为两种情况 return 和 List[Any] 仍然是相同类型的 ls: List[Any].

但是为什么 Some[String]NoneList[Any]flatMap 中是可以接受的?

此外,似乎 None 被完全忽略,而不是被视为一个重要的值?我在想可能有一些压缩步骤可以摆脱这些值,比如:

[1,2,3].concat([,,2,2])
// => (6) [1, 2, 3, empty × 2, 2]
[1,2,3].concat([,,4]).filter(Boolean)
// => (4) [1,2,3,4]

谁能解释一下这些?谢谢!!!

As I thought, flatMap works on some kinds of monad which works as a transformation from M[M[A]] -> M[A].

Scala flatMap 更通用(有些人不喜欢)。

如果您查看它们之间的 documentation, it's enough for the function passed to List#flatMap to return GenTraversableOnce[SomeType], not List[SomeType]. And even though Option doesn't extend GenTraversableOnce, there is an implicit conversion,它会在此处应用。

Besides, it seems like None is completely ignored rather then treated as a serious value ?

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]].

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

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

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