如何用 for-comprehension 表达以下嵌套的 futures

How to express the following nested futures with for-comprehension

我的问题:是否可以用 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
      }
    }
  })
})

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

for-comprehension 在您不将 SeqLike 单子与 non-SeqLike 单子混合之前很有用。但是一旦你把它们混合在一起,你就回到了嵌套世界。而且它会比以前更糟糕,因为 for-comprehensions 隐藏了细节。

让我们举一些例子,

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)`

以上代码不会编译,实际上也不应该编译。因为 Future 是一个 non-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-MonadsFutureflatMapflatten 以及 map 的实现非常不同。

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