了解展平的语义

Understanding the semantics of flatten

大多数教科书将 flatMap 描述为 flattenmap 的组合。虽然 map 并不难理解,但当谈到 flatten 的语义时(对我来说)事情就变得不太清楚了。特别是,我不明白为什么可以展平 List(Option(3)),而不可能在 Option(List(3)) 上做同样的事情。有人可以澄清一下吗?

scala> List(Option(3)).flatten
res9: List[Int] = List(3)

scala> Option(List(3)).flatten
<console>:12: error: Cannot prove that List[Int] <:< Option[B].
       Option(List(3)).flatten
                       ^

List[Int] <:< Option[B]中的<:<表示"is an approximate subtype."flatten要求里面的类型可以转换成外面的类型。对于 ListsOptions,这种转换只能进行一种方式。 Option(3) 可以转换为 List(3),但 List(1,2,3,4) 不能转换为 Option(1,2,3,4),因为 Options 最多只能容纳一个项目。

如果你在第二个选项的列表中有多个项目会发生什么?......没有从 Iterable(例如 List)到 Option 的隐式转换,因为在编译期间无法确保Iterable 有一个或 cero 项目,它可能有更多等等,不可能转换为 Option。这就是它背后的理念。

它背后的机制是 implicits,class <:<[A,B](是的,它是一个 class,名称为 <:<,可以是sugared 到 A <:< B),以及一个从 Option 到 Iterable 的隐式方法。

所以方法 flatten 的问题是它需要隐式类型(在您的情况下)<:<[List[Int],Option[Int]]<:<[Option[Int],List[Int]].

class 只有一个定义,而且它只适用于 <:<[A,A]。这样编译只能在您使用相同的 class 时找到证据,而不是这种情况。但是如果之前,Option被转换为Traversable,那么编译器就可以找到一个证据 <:<[Traversable[Int],Traversable[Int]]... Option 存在这样的隐式转换,并且 List 已经是一个 Traversable。 在这种情况下,存在从 Option[A]Traversable[A] 的隐式转换,因此编译器使用它并找到 class <:<...希望它很清楚!

以防万一,检查this line of Scala's sourcecode