3

我有两个问题,但我希望答案是相互交织的。所以我在玩 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 我想知道为什么 Option 不继承特征:Seq 和 Set?Option 是一个 Seq 因为它保持顺序,它是一个 Set 因为它不包含重复项。通过 Seq 和 Set 它将继承自 Iterable 和 Traversable。

4

2 回答 2

7

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

然而,在更深层次上,重要的是要认识到 for-comprehensions 和map/flatMap一元操作。Monad 是不可互换的——你不能选择 aa 函数A => N[B]并将其传递给 anM[A]来获得 an N[B],对于任何 monad M 和 N,Optionand 集合是不同的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如果您将其视为最多一个元素的集合,这State可能对Reader.

说到思考,Option至多是一个的集合,这是不这样做的另一个原因。AnOption应该被认为是一个元素的存在或不存在,而不是一个集合,以及有助于这种微妙区别的可用方法。再说一次,我知道很多人认为这个论点,至少,完全是假的,所以持保留态度。

于 2013-10-23T20:29:03.637 回答
1

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

选项上的平面图定义如下

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

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

a.flatMap(s => s.toList)

不返回 Option[_] 而是返回一个字符列表(s 是一个字符串,s.toList 返回一个 List[Char])。

于 2013-10-23T19:57:35.817 回答