Scala - Option 上的 Map2 函数 --> flatMap vs. Map vs. For-Comprehension

Scala - Map2 function on Option --> flatMap vs. Map vs. For-Comprehension

Option在Scala中是用来处理偏向性的,但是我们也可以将普通的函数提升到Options的上下文中来处理错误。在实现函数 map2 时,我很好奇如何知道何时使用哪些函数。考虑以下实现:

def map2[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] =
    ao flatMap {aa =>
      bo map {bb =>
        f(aa, bb)

aa 是 A 类型,bb 是 B 类型,然后将其馈送到 F,给我们一个 C。但是,如果我们执行以下操作:

def map2_1[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] =
    ao flatMap {aa =>
      bo flatMap {bb =>
        f(aa, bb)

aa 仍然是 A 类型,bb 仍然是 B 类型,但我们必须将最后一次调用包装在 Some(f(aa, bb)) 中以获得 Option[C] 而不是一个普通的C。这是为什么?在这里压平BO是什么意思?

最后但同样重要的是,可以做更简单的事情:

def map2_2[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] = for {
    as <- ao 
    bs <- bo 
} yield(f(as,bs))

我知道 for-comprehensions 是 ForEach、maps 和 flatmaps 等的语法糖,但作为开发人员,我如何知道编译器会选择带有 bs <- bo 的 MAP,而不是 flatMap?

我想我即将理解其中的区别,但嵌套的平面图让我感到困惑。

先回答最后一个问题,开发人员知道编译器将如何处理 for,因为行为是已定义且可预测的:除最后一个外,所有 <- 都变成 flatMap这将是 mapforeach 取决于是否有 yield.

更广泛的问题似乎是关于 mapflatMap 之间的区别。从签名中应该可以清楚地看出区别,例如对于 List 这些是(简化的)签名:

def map[B]    (f: A => B)      : List[B]
def flatMap[B](f: A => List[B]): List[B]

所以 map 只是将 List 中的值替换为新值,方法是将 f 应用于 A 类型的每个元素以生成 B .

flatMap 通过连接对原始 List 的每个元素调用 f 的结果生成一个新列表。它相当于 map 后跟 flatten(因此得名)。

直觉上,map 是 one-for-one 替换,而 flatMap 允许原始 List 中的每个元素生成 0 个或更多新元素。