Monads - 扁平化的目的

Dan*_*Dan 1 monads scala flatmap

flatMap所以我一直在阅读一些关于 scala 中的 Monad 的文章,以及与其函数和理解相关的所有语法for。直观上,我理解为什么 Monad 需要使用函数map的一部分flatMap,就像通常当我map在零个、一个或多个元素的容器上使用函数时,它返回相同的容器,但传入的函数应用于所有元素容器。类似地,Monad 是零个、一个或多个元素的容器。

flatten然而,这部分的目的是什么flatMap?我无法理解其背后的直觉。对我来说,这似乎是额外的样板,需要传递所有函数来围绕其返回值创建一个容器/flatMap单子,只是让该容器立即被. 我想不出使用 的单个示例不能通过简单地替换为 来简化。例如:flattenflatMapflatMapmap

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
Run Code Online (Sandbox Code Playgroud)

对我来说,map单独使用似乎比该部分更直观和简单,flatMap并且该flatten部分似乎没有增加任何价值。然而,在 Scala 中,重点放在flatMap而不是map,以至于它甚至有自己的for理解语法,所以显然我一定错过了一些东西。我的问题是:在什么情况下这flatten部分flatMap实际上有用?flatMap相比之下还有什么优势呢map

jwv*_*wvh 5

如果正在处理的每个元素可能会产生零个或多个元素怎么办?

List(4, 0, 15).flatMap(n => primeFactors(n))
//List(2, 2, 3, 5)
Run Code Online (Sandbox Code Playgroud)

如果您有一个可能拼写不正确的名字,并且您想要他们的办公室分配(如果他们有的话)怎么办?

def getID(name:String): Option[EmployeeID] = ???
def getOffice(id:EmployeeID): Option[Office] = ???

val office :Option[Office] =
  getID(nameAttempt).flatMap(id => getOffice(id))
Run Code Online (Sandbox Code Playgroud)

flatMap()当您一个 monad 并且需要将其内容提供给 monad 生产者时,您可以使用它。你想要的结果Monad[X]不是Monad[Monad[X]]