2016-08-18 1 views
0

Meine Frage: Ist es möglich, diesen verschachtelten Ausdruck mit Verständnis zu vereinfachen?Wie die folgenden geschachtelten Futures mit Verständnis zu äußern

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 
     } 
    } 
    }) 
}) 
+1

Sie zeigen besser die Arten Ihrer Methoden oder vereinfachen Sie Ihre Frage. In dieser Form bekommst du kaum eine Antwort – Nyavro

+0

Bist du sicher, dass dieser Code funktioniert? –

+0

Sie haben falsch passende Klammern. Es ist unmöglich vorherzusagen, was Sie wollten. –

Antwort

1

Für Verständnisse sind mächtig, aber sie sind nicht ein allmächtiger Nesting-Killer, den Sie denken, dass sie sind.

for-comprehension sind nützlich, bis Sie nicht mischen SeqLike Monaden mit non-SeqLike Monaden. Aber sobald du sie vermischst, bist du zurück in der Nistwelt. Und es wird noch schlimmer als zuvor, weil die Nachforschungen die Details verbergen.

Lets einige Beispiele nehmen,

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) 

Jetzt Mix lässt List mit 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)` 

Der obige Code wird nicht kompiliert, und es sollte eigentlich nicht kompilieren. Als Future ist eine non-SeqLike Monade. Ich meine, wenn der obige Code funktioniert, wäre es ein Success(5, 6, 7), was keinen Sinn ergibt.

Ebenso wird folgender Code funktioniert nicht

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

Dieser Fall ist viel anders als die vorhergehenden, wie es dem gesunden Menschenverstand bestätigt, aber noch wird es nicht funktionieren. Der Grund ist, dass SeqLike-Monads und Future s sehr sehr unterschiedliche Implementierungen von flatMap und flatten und map haben.

Also ... wenn mit einer Mischung aus List tun haben, Future, Option, Try usw., bleiben von for-comprehension entfernt. Versuchen Sie einfach, Ihren Code cleverer zu schreiben.

+0

Um zu erweitern: Futures sind eigentlich keine Monaden. Sie haben nur monadähnliche Eigenschaften. Dies hat eine gute Diskussion http://stackoverflow.com/questions/27454798/is-future-in-scala-a-monad –

+0

Ja. Mathematisch Scala 'Future's können die Monade-Definition verletzen, da sie Nebenwirkungen zulassen. Aber die ganze reine Monaden-Diskussion gehört zur reinen funktionalen Programmierung, in der Nebenwirkungen als Todsünde behandelt werden. Wenn also ein funktionaler Purist 'Future' verwendet, wird er keine Nebenwirkungen verwenden und daher wird' Future' nicht die Monadengesetze verletzen. –

+0

ist es möglich, wie man Future {}. Map (a => a.map (b => b)) so weiter ausgibt, indem man irgendeine Art von syntaktischem Zucker verwendet? –