Scala 有连续的未来吗?

Scala 有连续的未来吗?,scala,stream,functional-programming,future,sequential,Scala,Stream,Functional Programming,Future,Sequential,我有一些副作用 def f(): Future[Int] = { val n = Random.nextInt() println(s"Generated $n") Future(n) } 我想重复执行它,直到谓词返回true def success(n: Int): Boolean = n % 2 == 0 scala> Future.find(s)(success) map println Generated -237492703 Generated -93547629

我有一些副作用

def f(): Future[Int] = {
  val n = Random.nextInt()
  println(s"Generated $n")
  Future(n)
}
我想重复执行它,直到谓词返回true

def success(n: Int): Boolean = n % 2 == 0
scala> Future.find(s)(success) map println
Generated -237492703
Generated -935476293
Generated -1155819556
Generated -375506595
Generated -912504491
Generated -1307379057
Generated -1522265611
Generated 1163971151
Generated -516152076
res8: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@37d28f02
Some(-1155819556)
我的计划是建立
结果流

val s = Stream.fill(10)(f)
然后使用
Future.find
获得满足谓词的第一个结果

Future.find(s)(success) map println
问题是
Future.find
并行运行所有期货,我希望它依次执行期货,直到谓词返回true为止

def success(n: Int): Boolean = n % 2 == 0
scala> Future.find(s)(success) map println
Generated -237492703
Generated -935476293
Generated -1155819556
Generated -375506595
Generated -912504491
Generated -1307379057
Generated -1522265611
Generated 1163971151
Generated -516152076
res8: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@37d28f02
Some(-1155819556)

问题是如何顺序执行未来流,直到谓词返回true为止?标准库或第三方库中是否有合适的函数?

首先,让我们让我们不感兴趣的未来失败:

val s1 = s.map(_.filter(success))
现在,您可以使用
fallbackTo
组合两个这样的期货并获得第一个成功的价值。从一个已知的坏未来开始

def firstSuccess[T](stream: Stream[Future[T]]): Future[T] = 
  if (stream.isEmpty)
    Future.failed(new NoSuchElementException)
  else
    stream.head.fallbackTo(firstSuccess(stream.tail))

如果我理解了这个问题,那么您必须阻塞线程才能继续。您可以使用wait来实现这一点

scala> def f(): Future[Int] = {
 |   val n = Random.nextInt()
 |   println(s"Generated $n")
 |   Future(n)
 | }
f: ()scala.concurrent.Future[Int]

scala> def success(n: Int): Boolean = n % 2 == 0
success: (n: Int)Boolean

scala> val s = Stream.fill(10)(f)
用你的方式,我得到

scala> Future.find(s)(success) map println
Generated 551866055
Generated -561348666
Generated -1103407834
Generated -812310371
Generated -1544170923
Generated 2131361419
Generated -236722325
Generated -1473890302
Generated -82395856
Some(-561348666)
res16: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@15a2d71
我应该得到一些答案(-561348666),你们可以得到

scala> s.find(x => success(Await.result(x,1 seconds))).get onSuccess {case p=> println(p)}
-561348666

我建议使用另一种方法,而不是使用流。以递归方式使用Future的筛选器和recoverWith:

def findFirst[A](futureGen: => Future[A], predicate: A => Boolean): Future[A] = {
  futureGen.filter(predicate).recoverWith { case _ => findFirst(futureGen, predicate) }
}

findFirst(f, success)

这将一个接一个地呼唤未来,直到“成功”回归现实

foldLeft
执行所有期货,但我希望执行足够的期货来满足谓词。@lambdas Oops。当然你是对的,你需要一个懒散的右折叠。编辑。再编辑一次,因为匹配流的模式不够懒。谢谢你的努力!我仍然认为使用标准库、scalaz、twitter futures或其他我不知道的东西,有一种更简单的方法来解决这个问题。哦,scalaz确实包含了惰性右折叠,称为
foldr
。我认为在我的原始解决方案中,用
foldr
替换
foldLeft
应该是可行的,模参数顺序。另请参见“我想获得Future[Option[Int]]”的答案,可以将最后一个表达式包装在
Future{…}
中吗<代码>未来与
等待
在一起,看起来很奇怪;)我不知道你要怎么用它。您可以包装表达式,但它可能正确,也可能不正确,这取决于您的用例。s、 find(x=>success(wait.result(x,1秒)).get返回未来[Int]您可以查看std-lib案例的
scalaz-stream
iteratee
replicate。看起来像是我当前使用的手工递归,除了
过滤器
recoverWith
:)好吧。。。有时候你应该坚持简单的解决方案。