【问题标题】:What does flatMap do exactly?flatMap 到底是做什么的?
【发布时间】:2015-11-28 12:32:29
【问题描述】:

对于学校的编码作业,我必须使用 flatmap 做一些事情,但我完全不知道它的作用,我已经在网上阅读了几页并在我的教科书中阅读,但我仍然没有真正理解它的作用.我知道 map 的作用,但由于某种原因,我很难将我的头绕在 flatmap 上。任何人都可以帮忙吗?谢谢。

只是为了添加更多信息-当我查看在线示例时,我确实看到了 flatmap 如何返回与 map 不同的东西。但是当 flatmap 被调用时,它实际上在做什么呢?平面图实际上是如何工作的?在返回结果之前它在做什么?

【问题讨论】:

  • 这不是 StackOverflow 的问题
  • 平面图 = 地图+展平
  • 那是什么类型的问题?
  • 在提问之前你应该先做自己的研究,因为flatMap 很容易成为最常用的函数式编程习惯,而且那里有成千上万的资源。好的开始是看看它是如何实际实现的,而不是阅读它是什么的抽象插图。

标签: scala flatmap


【解决方案1】:

这是一个类比。

想象一下,您有一个大袋子,里面装满了几盒鸡蛋的购物券。如果你有一个“使用代金券买一盒鸡蛋”的功能,并且你打电话给bigBagOfVouchers.map(buyCartonOfEggs),你就会有一袋鸡蛋。

但是,如果您致电 bigBagOfVouchers.flatMap(buyCartonOfEggs),您将得到一袋鸡蛋 - 没有任何纸箱。

flatMap 将结果平展一级。可能是 Bag[Carton[Egg]] 现在是 Bag[Egg]

【讨论】:

  • 是这样吗?我一直认为flatMap 要求“内部”单子与“外”单子的类型完全相同。不过,我猜你可能会说如果BagCarton 都是Iterable,它会起作用。
  • 基本上 .flatMap 只不过是 .map(x => something(x)).flatten 。我的假设是对的吗?
  • 没错。虽然,flatten 直到 v2.8 才存在 stackoverflow.com/questions/2895069/…
【解决方案2】:

函子定义具有类型的映射

trait Functor[F[_]] {
    def map[A, B](f: A => B)(v: F[A]): F[B]
}

Monad 是支持两个额外操作的函子:

trait Monad[M[_]] extends Functor[M] {
    def pure[A](v: A): M[A]
    def join[A](m: M[M[A]]): M[A]
}

Join 使嵌套值变平,例如如果mList 那么join 有类型

def joinList[A](l: List[List[A]]): List[A]

如果你有一个 monad m 而你 map 在它上面,如果 b 是同一个 monad 类型会发生什么?例如:

def replicate[A](i: Int, value: A): List[A] = ???
val f = new Functor[List] {
    def map[A, B](f: A => B)(v: List[A]) = v.map(f)
}

然后

f.map(x => replicate(x, x))(List(1,2,3)) == List(List(1), List(2,2), List(3,3,3))

它的类型为List[List[Int]],而输入为List[Int]。希望每个步骤返回相同的输入类型的操作链是相当常见的。因为List也可以做成一个monad,你可以很容易地使用join创建这样一个列表:

listMonad.join(List(List(1), List(2,2), List(3,3,3))) == List(1,2,2,3,3,3)

现在您可能想编写一个函数将这两个操作合二为一:

trait Monad[M] {
   def flatMap[A, B](f: A => M[B])(m: M[A]): M[B] = join(map(f)(m))
}

那么你可以简单地做:

listMonad.flatMap(List(1,2,3), x => replicate(x, x)) == List(1,2,2,3,3,3)

flatMap 的确切作用取决于 monad 类型构造函数 M(在此示例中为 List),因为它取决于 mapjoin

【讨论】:

  • 我无法想象这个关于 Monads 的讨论会帮助原始海报。
  • @alper - 你怎么能解释flatMap而不谈论单子?他们接受这个答案的事实表明他们确实觉得它很有帮助。
  • 我认为这是不必要的蒙昧主义者,因为 monad 本身也没有在任何地方得到正确解释。
  • 举个例子,这是相反的定义:chris.eidhof.nl/post/monads-in-swift
  • @alper - 该链接根本无法解释 flatMap 的作用。这个答案解释了Monads 是什么(具有两个额外操作purejoin 的函子)然后根据Monad 支持的两个操作(mapjoin)定义flatMap。唯一缺少的是您的链接也没有提及的单子定律。
【解决方案3】:

在响应式编程中,经常会遇到需要使用flatMapFuture[Future[List]]转换为Future[List ]。例如,您有两个函数:get 来自数据库的用户和 process 检索的用户;并且都返回 Future[List[User]]。如果将 ma​​p 应用到 getprocess,结果将是 Future[Future[List[User]]]] 这没有任何意义。相反,您应该使用 flatMap:

def main(): Future[List[User]] = getUsers flatMap processUsers    
def getUsers: Future[List[User]]
def processUsers(users: List[User]): Future[List[User]]

【讨论】:

    猜你喜欢
    • 2015-08-06
    • 2013-09-02
    • 2014-01-02
    • 2013-10-10
    • 2017-05-08
    • 2022-01-20
    • 2012-10-17
    • 2017-06-15
    • 2011-05-20
    相关资源
    最近更新 更多