【问题标题】:How to express the following nested futures with for-comprehension如何用 for-comprehension 表达以下嵌套的期货
【发布时间】:2016-12-25 04:40:11
【问题描述】:

我的问题:是否可以用 for-comprehension 来简化这个嵌套表达式?

run(dbAction).flatMap(insertedJobs => {
  Future.sequence(insertedJobs.map { job =>
    recordingBean.findStreamsForInterval(job.mediaSource, job.begin, job.end) map { stream =>
      if (stream.nonEmpty) {
        recordingBean.findRecordingLocationsForInterval(stream.head.stream, job.begin, job.end).map(recordingLocations =>
          recordingLocations.map(_.size.getOrElse(0L)).sum).flatMap { expectedSizeInBytes =>
          updateSize(job.id.get, expectedSizeInBytes)
        }
        job
      } else {
        job
      }
    }
  })
})

【问题讨论】:

  • 您最好显示您的方法类型或简化您的问题。在这种形式下,你几乎得不到任何答案
  • 你确定这段代码有效吗??
  • 您的括号不匹配。无法预测您想要什么。

标签: scala for-loop dictionary future flatmap


【解决方案1】:

因为推导很强大,但它们并不是你认为的万能的嵌套杀手。

for-comprehension 非常有用,除非您不将 SeqLike monads 与 non-SeqLike monads 混合使用。但是一旦你混合它们,你就回到了嵌套世界。而且它会比以前更糟,因为理解隐藏了细节。

让我们举几个例子,

val listOfListOfInt = List(List(1, 2, 3), List(2, 3, 4))

val listOfInt = for {
  loi <- listOfListOfInt
  i <- loi
} yield i + 4

// This will work just fine
// listOfInt: List[Int] = List(5, 6, 7, 6, 7, 8) 

现在让我们将ListFuture 混合,

val futureOfList = Future({ List(1, 2, 3) })

val iWillNotCompile = for {
  l <- futureOfList
  i <- list
} yield i + 4

// the above is equivalent to writing,
val iWillNotCompile = futureOfList.flatMap(l => l.map(i => i + 4))

// would have been following but does not make sense
// `Success(5, 6, 7)`

上面的代码不会编译,实际上它不应该编译。因为Futurenon-SeqLike monad。我的意思是,如果上面的代码有效,那将是 Success(5, 6, 7),这没有意义。

同样,下面的代码也不起作用

val listOfFuture = List(Future({ 1 }), Future({ 2 }), Future({ 3 }) )

val iWillNotCompile = for {
  f <- listOfFuture
  i <- f
} yield i + 4

// this is equivalent to
val iWillNotCompile = listOfFuture.flatMap(f => f.map(i => i + 4)

// should have been following and it makes sense
// List(Success(5), Success(6), Success(7))

这个案例与前一个案例有很大不同,因为它符合常识,但仍然无法正常工作。原因是SeqLike-MonadsFutures 对flatMapflattenmap 的实现非常不同。

所以...如果正在处理ListFutureOptionTry 等的混合,请远离for-comprehension。尝试以更聪明的方式编写代码。

【讨论】:

  • 扩展:Futures 实际上不是 Monad。它们只有类似单子的属性。这有一个很好的讨论stackoverflow.com/questions/27454798/is-future-in-scala-a-monad
  • 是的。数学上 Scala Futures 可能违反 monad 定义,因为它们允许副作用。但是整个纯单子讨论属于纯函数式编程,其中副作用被视为致命的罪过。因此,如果功能纯粹主义者使用 Futures,他将不会使用副作用,因此 Futures 不会违反单子定律。
  • 是否有可能使用某种语法糖来表达 Future{}.map(a => a.map(b => b)) end 等等?
  • @SlowHarry Syntactic Sugar 正是我建议您避免的。语法糖的问题在于,它们的实现在某些情况下混合了通用 + 特殊处理。 Scala 语法糖以不可预测(有太多特殊情况)而闻名。请记住,神奇的代码并不是最容易理解的代码。
猜你喜欢
  • 2015-01-21
  • 1970-01-01
  • 2015-11-07
  • 2018-04-26
  • 2016-11-10
  • 2017-04-08
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多