为什么Option不从Seq和Set继承?

时间:2013-10-23 19:40:19

标签: scala inheritance scala-collections

我有两个问题,但我希望答案交织在一起。所以我正在玩flatMapping不同的参数类型。我得到以下内容:

val s: List[String] = List("f2", "df", "e")     //> s  : List[String] = List(f2, df, e)
val o = s.map(s => if (s.head == 'f')Some(s) else None)
                                              //> o  : List[Option[String]] = List(Some(f2), None, None)
val o1 = s.flatMap(s => if (s.head == 'f')Some(s) else None)
                                              //> o1  : List[String] = List(f2)
val a: Option[String] = Some("Hello")           //> a  : Option[String] = Some(Hello)
val a1 = a.map(s => s.toList)                   //> a1  : Option[List[Char]] = Some(List(H, e, l, l, o))

val a2 = a.flatMap(s => s.toList) //gives
//type mismatch;  found   : List[Char]  required: Option[?]

所以我试图理解o1编译背后的逻辑而不是a2。然后调查选项我想知道为什么Option不继承特性:Seq和Set? Option是Seq,因为它维护顺序,它是一个Set,因为它不包含重复项。通过Seq和Set,它将继承自Iterable和Traversable。

2 个答案:

答案 0 :(得分:7)

所有GenTraversableOnce后代的假设是它们包含任意个元素。有太多的API和假设或依赖于此的机制,例如BuilderCanBuildFrom

然而,在更深层次上,重要的是要认识到for-comprehensions和map / flatMap monadic 操作。 Monads不可互换 - 你不能选择一个函数A => N[B]并将其传递给M[A]以获得N[B],对于任何monad M和N,以及Option和集合是不同的 monad。

通过许多隐含的魔法,所有集合都被视为单个monad,这导致人们假设所有monad 可以互换,而事实并非如此。

然后考虑这样一个简单的案例:

val x = Option(1)
val y = List('a', 'b', 'c')
val z = for {
  a <- x
  b <- y
} yield (a, b)

z 的类型不能Option,因为结果有多个元素。它工作的唯一方法是使它成为类似Iterable的东西。这可能对Option有意义,如果你把它看作最多一个元素的集合,但对于像StateReader monad这样的东西没有意义。 / p>

谈到将Option视为最多一个的集合,这是不这样做的另一个原因。 Option应该被认为是元素的存在与否,而不是集合,以及可用于帮助这种微妙区别的方法。再说一次,我知道有很多人认为这个论点至少是完全虚假的,所以要把它当作一粒盐。

答案 1 :(得分:1)

虽然可以映射选项,但它不是序列也不是集合(只有一个元素)。

选项上的平面地图定义如下

flatMap[B](f: (A) ⇒ Option[B]): Option[B]

所以它想要一个返回另一个Option的函数。你的代码

a.flatMap(s => s.toList)

不返回Option [_]但返回字符列表(s是String,s.toList返回List [Char])。