如何用 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)
现在让我们将 List
与 Future
、
混合
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-Monads
和 Future
对 flatMap
和 flatten
以及 map
的实现非常不同。
所以...如果要处理 List
、Future
、Option
、Try
等的混合,请远离 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)
现在让我们将 List
与 Future
、
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-Monads
和 Future
对 flatMap
和 flatten
以及 map
的实现非常不同。
所以...如果要处理 List
、Future
、Option
、Try
等的混合,请远离 for-comprehension
。尝试以更聪明的方式编写代码。