2014-10-18 61 views
3

我有一些副作用effectful功能,有沒有連續的Future.find?

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

,我想直到謂詞返回true反覆執行它。

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

我的計劃是構建結果

Stream
val s = Stream.fill(10)(f) 

,然後使用Future.find率先拿到結果是滿足謂詞。

Future.find(s)(success) map println 

的問題是,Future.find運行所有期貨並行,我想它,直到謂詞返回true後,其他順序執行的道路。

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] = [email protected] 
Some(-1155819556) 

問題是如何順序執行期貨流,直到謂詞返回true?標準或第三方庫中是否有適合的功能?

+0

您可能需要查看'scalaz-stream'或'iteratee' – jilen 2014-10-18 16:39:50

+0

複製std lib的情況。 http://stackoverflow.com/questions/26349318/how-to-invoke-a-method-again-and-again-until-it-returns-a-future-value-contain – 2014-10-18 22:41:37

回答

1

首先,讓我們做,我們不感興趣的失敗期貨:

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)) 
+0

'foldLeft'執行所有期貨,但我希望執行足夠的期貨來滿足謂詞。 – lambdas 2014-10-18 14:26:42

+0

@lambdas哎呀。當然你是對的,你需要一個懶惰的正確摺疊。編輯。 – 2014-10-18 15:58:54

+0

並且再次編輯,因爲與流匹配的模式不夠懶。 – 2014-10-18 16:01:59

0

如果我理解了這個問題,那麼您將不得不阻止線程按順序繼續。你可以使用等待來完成。

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] = [email protected] 

我應該得到的答案有些(-561348666),你可以得到儘可能

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

我想獲得Future [Option [Int]],可以將最後一個表達式包裝在'Future {...}'中嗎? '未來'裏面有'Await',看起來很奇怪;) – lambdas 2014-10-18 16:03:50

+0

我不知道你要用它的方式。您可以包裝表達式,但根據您的使用情況,它可能會或可能不會正確。 s.find(x => success(Await.result(x,1 seconds)))。get returns Future [Int] – mohit 2014-10-18 16:09:01

4

而不是使用流的,我建議使用另一種方法。使用未來的過濾器和recoverWith遞歸:

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

findFirst(f, success) 

這將調用期貨一個接一個,直到「成功」後,將返回true。

+0

看起來像我目前使用的手工遞歸,除了'filter'和'recoverWith': ) – lambdas 2014-10-19 06:28:16

+0

呃...有時候你應該堅持簡單的解決方案。 – roterl 2014-10-19 06:41:18