Scala 中条件期货的组成
Composition of Conditional Futures in Scala
我有一些代码适用于一个简单的案例(2 个 Futures),但我无法找到将它推广到无限数量的 Futures 的方法。
我想做的是创建一些调用未来的代码,当那个未来完成时,调用另一个,当这个完成时调用另一个,依此类推。
我需要在调用下一个之前完成每个调用的结果,因为我可能不需要再次调用它(这是我的停止条件)。
I know this can be solved explicitly with recursion, but I would like, if at all possible, a solution using for comprehensions and/or folds. I feel there must be a solution like that but I can't write it correctly.
这是一个生成两个随机整数列表的函数
def nextValue: Future[List[Int]] = Future{
Thread.sleep(1000)
val num1 = Random.nextInt(10)
val num2 = Random.nextInt(10)
List(num1,num2)
}
现在我想组成无限多个这样的期货并在最后加入它们(列表的单个期货)
I'm just calling await.result for testing purposes
这适用于 2 个级别,但如何将其概括为 N 个调用?
Await.result({
nextValue.flatMap{ value1 =>
nextValue.map{ value2 =>
value1 ++ value2
}
}
},1.minute)
Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten)
用法:
scala> Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten)
res3: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[Int]] = scala.concurrent.impl.Promise$DefaultPromise@692e028d
scala> Await.result(res3, duration.Duration.Inf)
res4: scala.collection.immutable.IndexedSeq[Int] = Vector(5, 4, 3, 0, 4, 6, 0, 8, 0, 0, 4, 6, 2, 7, 4, 9, 8, 8, 6, 9, 1, 4, 5, 5, 8, 2, 2, 7, 6, 0, 5, 6, 6, 5, 9, 6, 3, 5, 7, 1, 3, 2, 5, 3, 3, 1, 8, 4, 6, 7, 5, 1, 3, 5, 7, 4, 1, 5, 9, 4, 5, 0, 1, 8, 5, 0, 0, 7, 4, 2, 4, 2, 2, 0, 4, 1, 6, 3, 8, 2, 1, 3, 5, 5, 8, 3, 6, 1, 3, 2, 9, 4, 9, 4, 7, 5, 7, 8, 7, 9, 5, 2, 5, 0, 2, 5, 6, 8, 6, 2, 3, 2, 0, 8, 9, 3, 9, 2, 7, 5, 1, 7, 1, 1, 8, 6, 8, 0, 5, 5, 6, 0, 8, 8, 3, 6, 4, 2, 7, 1, 0, 3, 3, 3, 3, 2, 8, 7, 3, 3, 5, 1, 6, 3, 3, 7, 8, 9, 9, 9, 1, 9, 9, 8, 1, 1, 5, 8, 1, 1, 7, 6, 3, 2, 5, 0, 4, 3, 0, 9, 9, 1, 2, 0, 3, 6, 2, 6, 8, 6, 6, 3, 9, 7, 1, 3, 5, 9, 6, 5, 6, 2)
或 scalaz/cats:
//import scalaz._,Scalaz._
// --or--
//import cats.syntax.traverse._
//import cats.std.list._
//import cats.std.future._
(0 to 100).toList.traverseM(_ => nextValue)
来自 here 的解释:
traverseM(f) is equivalent to traverse(f).map(_.join), where join is
the scalaz name for flatten. It's useful as a kind of "lifting
flatMap":
如果你想要一些条件并且仍然需要保持异步,你可以使用 fs2:
import fs2._
import fs2.util._
def nextValue: Task[List[Int]] = Task.delay{
import scala.util.Random
val num1 = Random.nextInt(10)
val num2 = Random.nextInt(10)
if(num1 > 5) List(num1,num2) else List()
}
Stream.repeatEval(nextValue).takeWhile(_.size > 0).runLog.map(_.flatten).unsafeRun
https://github.com/functional-streams-for-scala/fs2/blob/series/0.9/docs/guide.md
同样可以用 Iteratees 实现:
猫:https://github.com/travisbrown/iteratee
或 scalaz-iteratee 包
一般来说,你不能用 fold
实现这个,因为它实际上是 unfold
并且在 scala 中没有很好的展开支持,因为标准库的 Stream
不能概括在 Monad/ApplicativeFunctor 上(就像 EnumeratorT
那样)- 您只能通过在每个展开步骤上执行 Await.result
来检查条件。
我有一些代码适用于一个简单的案例(2 个 Futures),但我无法找到将它推广到无限数量的 Futures 的方法。
我想做的是创建一些调用未来的代码,当那个未来完成时,调用另一个,当这个完成时调用另一个,依此类推。
我需要在调用下一个之前完成每个调用的结果,因为我可能不需要再次调用它(这是我的停止条件)。
I know this can be solved explicitly with recursion, but I would like, if at all possible, a solution using for comprehensions and/or folds. I feel there must be a solution like that but I can't write it correctly.
这是一个生成两个随机整数列表的函数
def nextValue: Future[List[Int]] = Future{
Thread.sleep(1000)
val num1 = Random.nextInt(10)
val num2 = Random.nextInt(10)
List(num1,num2)
}
现在我想组成无限多个这样的期货并在最后加入它们(列表的单个期货)
I'm just calling await.result for testing purposes
这适用于 2 个级别,但如何将其概括为 N 个调用?
Await.result({
nextValue.flatMap{ value1 =>
nextValue.map{ value2 =>
value1 ++ value2
}
}
},1.minute)
Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten)
用法:
scala> Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten)
res3: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[Int]] = scala.concurrent.impl.Promise$DefaultPromise@692e028d
scala> Await.result(res3, duration.Duration.Inf)
res4: scala.collection.immutable.IndexedSeq[Int] = Vector(5, 4, 3, 0, 4, 6, 0, 8, 0, 0, 4, 6, 2, 7, 4, 9, 8, 8, 6, 9, 1, 4, 5, 5, 8, 2, 2, 7, 6, 0, 5, 6, 6, 5, 9, 6, 3, 5, 7, 1, 3, 2, 5, 3, 3, 1, 8, 4, 6, 7, 5, 1, 3, 5, 7, 4, 1, 5, 9, 4, 5, 0, 1, 8, 5, 0, 0, 7, 4, 2, 4, 2, 2, 0, 4, 1, 6, 3, 8, 2, 1, 3, 5, 5, 8, 3, 6, 1, 3, 2, 9, 4, 9, 4, 7, 5, 7, 8, 7, 9, 5, 2, 5, 0, 2, 5, 6, 8, 6, 2, 3, 2, 0, 8, 9, 3, 9, 2, 7, 5, 1, 7, 1, 1, 8, 6, 8, 0, 5, 5, 6, 0, 8, 8, 3, 6, 4, 2, 7, 1, 0, 3, 3, 3, 3, 2, 8, 7, 3, 3, 5, 1, 6, 3, 3, 7, 8, 9, 9, 9, 1, 9, 9, 8, 1, 1, 5, 8, 1, 1, 7, 6, 3, 2, 5, 0, 4, 3, 0, 9, 9, 1, 2, 0, 3, 6, 2, 6, 8, 6, 6, 3, 9, 7, 1, 3, 5, 9, 6, 5, 6, 2)
或 scalaz/cats:
//import scalaz._,Scalaz._
// --or--
//import cats.syntax.traverse._
//import cats.std.list._
//import cats.std.future._
(0 to 100).toList.traverseM(_ => nextValue)
来自 here 的解释:
traverseM(f) is equivalent to traverse(f).map(_.join), where join is the scalaz name for flatten. It's useful as a kind of "lifting flatMap":
如果你想要一些条件并且仍然需要保持异步,你可以使用 fs2:
import fs2._
import fs2.util._
def nextValue: Task[List[Int]] = Task.delay{
import scala.util.Random
val num1 = Random.nextInt(10)
val num2 = Random.nextInt(10)
if(num1 > 5) List(num1,num2) else List()
}
Stream.repeatEval(nextValue).takeWhile(_.size > 0).runLog.map(_.flatten).unsafeRun
https://github.com/functional-streams-for-scala/fs2/blob/series/0.9/docs/guide.md
同样可以用 Iteratees 实现:
猫:https://github.com/travisbrown/iteratee 或 scalaz-iteratee 包
一般来说,你不能用 fold
实现这个,因为它实际上是 unfold
并且在 scala 中没有很好的展开支持,因为标准库的 Stream
不能概括在 Monad/ApplicativeFunctor 上(就像 EnumeratorT
那样)- 您只能通过在每个展开步骤上执行 Await.result
来检查条件。