2016-07-01 15 views
0

Ich habe einige Code, der für einen einfachen Fall (2 Futures) funktioniert, aber ich kann nicht den Weg finden, es für eine unbegrenzte Anzahl von Futures zu verallgemeinern.Zusammensetzung der bedingten Futures in Scala

Ich möchte Code erstellen, der eine Zukunft aufruft, und, wenn diese Zukunft abgeschlossen ist, eine andere anrufen, und wenn diese abgeschlossen ist, eine andere anrufen, und so weiter.

Ich brauche das Ergebnis jedes Anrufs vor dem Aufruf des nächsten Anrufs abgeschlossen zu sein, da ich es möglicherweise nicht erneut aufrufen muss (dies ist meine Stoppbedingung).

Ich weiß, dass dies explizit mit Rekursion gelöst werden kann, aber ich möchte, wenn überhaupt möglich, eine Lösung für das Verständnis und/oder Falten. Ich denke, dass es eine solche Lösung geben muss, aber ich kann sie nicht richtig schreiben.

Hier aa Funktion, die ich mag komponieren unendlich viele solche Futures und kommen sie alle am Ende (eine einzige Zukunft einer Liste)

aa Liste von zwei zufällig Ints

def nextValue: Future[List[Int]] = Future{ 
    Thread.sleep(1000) 
    val num1 = Random.nextInt(10) 
    val num2 = Random.nextInt(10) 
    List(num1,num2) 
} 

Jetzt erzeugt

bin ich Aufruf await.result nur für Testzwecke

Dies funktioniert für 2 l Evels, aber wie man es für N Anrufe verallgemeinert?

Await.result({ 
    nextValue.flatMap{ value1 => 
    nextValue.map{ value2 => 
     value1 ++ value2 
    } 
    } 
},1.minute) 
+0

Wenn jedes 'Future' erst nach dem vorherigen gestartet wird, was bringt es,' Future' überhaupt zu verwenden? Könntest du eine "Falte" oder einen "Stream" in eine einzelne "Zukunft" wickeln, die fertiggestellt wird, wenn die Stoppbedingung erfüllt ist? – jwvh

Antwort

1
Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten) 

Verbrauch:

scala> Future.sequence((0 to 100).map(_ => nextValue)).map(_.flatten) 
res3: scala.concurrent.Future[scala.collection.immutable.IndexedSeq[Int]] = [email protected] 

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) 

Oder mit scalaz/Katzen:

//import scalaz._,Scalaz._ 
// --or-- 
//import cats.syntax.traverse._ 
//import cats.std.list._ 
//import cats.std.future._ 

(0 to 100).toList.traverseM(_ => nextValue) 

Eplanation von here:

traverseM (f) equival ent zu traversieren (f) .map (_. join), wobei join der scalaz-Name für flatten ist. Es ist nützlich, als eine Art "Hebe flatMap":

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

:


Wenn Sie eine Bedingung wollen und brauchen noch async zu bleiben, Sie fs2 verwenden können Dasselbe kann mit Iteraten erreicht werden:

Katzen: https://github.com/travisbrown/iterateePaketoder scalaz-iteratee

Allgemeinen Sie dies mit fold nicht umsetzen können, weil es tatsächlich unfold ist und es gibt keine gute Unterstützung für entfalten sich in scala als Standardbibliothek Stream kann keine Monade/ApplicativeFunctor verallgemeinern über (wie EnumeratorT does) - Sie können eine Bedingung nur überprüfen, indem Sie Await.result bei jedem Entfaltungsschritt tun.

+0

Ich dachte, dass das OP nach einer Sammlung von Länge suchte, die durch eine Ausgangsbedingung bestimmt ist, d. H. Hol 'nextValue, bis wir das Terminusergebnis erhalten. – jwvh

+0

Sie haben Recht, ich habe die Frage nicht sorgfältig gelesen - wird meine Antwort aktualisieren – dk14

+0

yeah ... Ich möchte das Ergebnis von getNext testen, um zu sehen, ob es gültig ist und zu beenden, wenn es nicht ist. Ist das möglich? –