如何解决Monads - Flatten 的目的
所以我一直在阅读有关 Scala 中的 Monads 以及与它们的 flatMap
函数和 for
推导式相关的所有语法。直觉上,我理解为什么 Monads 需要使用 map
函数的 flatMap
部分,就像通常当我在一个包含零个、一个或多个元素的容器上使用 map
函数并返回时一样同一个容器,但传入的函数应用于容器的所有元素。 Monad 类似地是一个包含零个、一个或多个元素的容器。
但是,flatten
的 flatMap
部分的用途是什么?我无法理解它背后的直觉。对我来说,这似乎是额外的样板,需要传递给 flatMap
的所有函数围绕其返回值创建一个容器/monad 只是为了让该容器立即被 {{1} 的 flatten
部分销毁}.我想不出一个使用 flatMap
的例子,它不能通过简单地替换为 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
部分似乎没有增加任何价值。然而,在 Scala 中,重点放在 flatten
而不是 flatMap
,以至于它甚至为 map
推导式提供了自己的语法,所以很明显我一定遗漏了一些东西。我的问题是:在什么情况下 for
的 flatten
部分实际上有用? flatMap
与 flatMap
相比还有哪些其他优势?
解决方法
如果正在处理的每个元素都可能产生零个或多个元素怎么办?
def getID(name:String): Option[EmployeeID] = ???
def getOffice(id:EmployeeID): Option[Office] = ???
val office :Option[Office] =
getID(nameAttempt).flatMap(id => getOffice(id))
如果您有一个可能拼写不正确的名字,并且您想要他们的办公室分配(如果他们有)怎么办?
flatMap()
当您拥有一个 monad 并且需要将其内容提供给 monad 生产者时,您可以使用 Monad[X]
。您想要结果 Monad[Monad[X]]
而不是 {{1}}。
flatMap
背后的想法是能够取值 M[A]
和类型为 f
的函数 A => M[B]
并生成 M[B]
,如果我们没有办法 "flatten"
值,那么我们最终总是会得到一个 M[M[B]]
,而这在大多数情况下是我们不想要的。
(是的,在某些情况下,您可能需要一个 M[M[_]]
,例如您想创建多个 M[_]
实例)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。