首页 > 解决方案 > Monads 是一种用于排序计算的机制,下面的列表是否仍然是一个 monad,尽管它们是以随机顺序打印的 Scala

问题描述

for {
    i <- 1 to 5
  } yield Future(println(i))

转为:

List(1,2,3,4,5).map {i => Future(println(i))}

上面的代码以随机顺序打印数字。

现在,如果我们看到 Monad 的多个定义: a) Monad 是对象的包装器 b) Monad 是一种用于排序计算的机制

我要回答的问题是,List monad 上的映射操作不应该等待列表中的第一个元素被打印出来,然后才去计算第二个元素,而不管未来如何?

对不起,这可能很简单,我把它复杂化了,但我很难找到简单的推理。答案将不胜感激:)

标签: scalamonadsfuturesequentialfor-comprehension

解决方案


相比:

for {
  _ <- Future(println(1))
  _ <- Future(println(2))
  _ <- Future(println(3))
  _ <- Future(println(4))
  _ <- Future(println(5))
} yield ()

或者

Future(println(1)).flatMap { _ =>
  Future(println(2))
}.flatMap { _ =>
  Future(println(3))
}.flatMap { _ =>
  Future(println(4))
}.flatMap { _ =>
  Future(println(5))
}

List(
  Future(println(1)),
  Future(println(2)),
  Future(println(3)),
  Future(println(4)),
  Future(println(5))
)

Future只有在前者完成并提供结果后,前两个才会创建下一个。最后一个同时创建所有Futures (在这方面它与您的示例没有太大区别List[Future])。

Future(与IOCa​​ts Effect、Monix'sTask或 ZIO 不同)是渴望的,因此它会在您创建它的那一刻开始执行。出于这个原因,前两个示例中有顺序结果,第三个示例中有随机顺序(竞争条件)。

如果你使用它IO而不是Future它会更明显,因为你不能仅仅拥有List[IO[Unit]]和执行副作用 - 你必须以某种方式将不同的 IO 组合成一个,并且你这样做的方式会很明显是否效果将是顺序的或并行的。

底线是 - 是否Future是 monad 取决于它的.flatMap行为方式(以及它与 组合的行为方式Future.successful),因此您的结果不会使Future作为 monad 的声明无效。(如果您开始检查它的异常行为,您可能会有一些疑问,但这是另一个话题)。


推荐阅读