【发布时间】:2021-05-05 07:22:17
【问题描述】:
所以我一直在阅读有关 Scala 中的 Monads 以及与它们的 flatMap 函数和 for 理解相关的所有语法。直观地说,我理解为什么 Monads 需要使用 flatMap 函数的 map 部分,就像我通常在使用 map 函数时一样,它在一个包含零个、一个或多个元素的容器上并返回相同的容器,但带有传入的函数应用于容器的所有元素。 Monad 同样是一个包含零个、一个或多个元素的容器。
但是,flatMap 的 flatten 部分的用途是什么?我无法理解它背后的直觉。对我来说,这似乎是额外的样板文件,需要传递给flatMap 的所有函数围绕它们的返回值创建一个容器/monad,只是为了让该容器立即被flatMap 的flatten 部分销毁。我想不出一个使用flatMap 的示例,它不能通过简单地替换为map 来简化。例如:
var monad = Option(5)
var monad2 = None
def flatAdder(i:Int) = Option(i + 1)
def adder(i:Int) = i + 1
// What I see in all the examples
monad.flatMap(flatAdder)
// Option[Int] = Some(6)
monad.flatMap(flatAdder).flatMap(flatAdder)
// Option[Int] = Some(7)
monad2.flatMap(flatAdder)
// Option[Int] = None
monad2.flatMap(flatAdder).flatMap(flatAdder)
// Option[Int] = None
// Isn't this a lot easier?
monad.map(adder)
// Option[Int] = Some(6)
monad.map(adder).map(adder)
// Option[Int] = Some(7)
monad2.map(adder)
// Option[Int] = None
monad2.map(adder).map(adder)
// Option[Int] = None
对我来说,单独使用map 似乎比flatMap 更直观和简单,而flatten 部分似乎没有增加任何价值。然而,在 Scala 中,重点放在flatMap 而不是map,以至于它甚至有自己的for 解析语法,所以很明显我一定遗漏了一些东西。我的问题是:在什么情况下,flatMap 的 flatten 部分实际上有用?以及flatMap 比map 有哪些其他优势?
【问题讨论】:
-
如果那是您经常看到的示例,恕我直言,示例 (可能是教程) 很糟糕,因为正如您所说,没有任何意义创建一个容器来将其展平。 -
flatMap的更好示例是使用 List 替换嵌套循环,使用 Option 组合无法返回值的多个函数,使用 Either 组合验证b>,使用 Future 组合异步调用。 - 无论如何是的,如果您不需要创建内部 "container" 则不要这样做,但现实是大多数时候A => F[B]函数很常见