了解展平的语义
Understanding the semantics of flatten
大多数教科书将 flatMap
描述为 flatten
和 map
的组合。虽然 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
要求里面的类型可以转换成外面的类型。对于 Lists
和 Options
,这种转换只能进行一种方式。 Option(3)
可以转换为 List(3)
,但 List(1,2,3,4)
不能转换为 Option(1,2,3,4)
,因为 Options
最多只能容纳一个项目。
如果你在第二个选项的列表中有多个项目会发生什么?......没有从 Iterable(例如 List)到 Option 的隐式转换,因为在编译期间无法确保Iterable 有一个或 cero 项目,它可能有更多等等,不可能转换为 Option。这就是它背后的理念。
它背后的机制是 implicit
s,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。
大多数教科书将 flatMap
描述为 flatten
和 map
的组合。虽然 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
要求里面的类型可以转换成外面的类型。对于 Lists
和 Options
,这种转换只能进行一种方式。 Option(3)
可以转换为 List(3)
,但 List(1,2,3,4)
不能转换为 Option(1,2,3,4)
,因为 Options
最多只能容纳一个项目。
如果你在第二个选项的列表中有多个项目会发生什么?......没有从 Iterable(例如 List)到 Option 的隐式转换,因为在编译期间无法确保Iterable 有一个或 cero 项目,它可能有更多等等,不可能转换为 Option。这就是它背后的理念。
它背后的机制是 implicit
s,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。