web-dev-qa-db-ja.com

Scalaの先物との「理解のため」

Scala Cookbook( http://shop.oreilly.com/product/0636920026914.do )を読んでいます。

理解に関係する将来の使用に関連する例があります。

これまでの理解に対する私の理解は、コレクションで使用すると、同じタイプの別のコレクションが生成されることです。たとえば、各futureXのタイプがFuture[Int]、次のタイプもFuture[Int]

for {
   r1 <- future1
   r2 <- future2
   r3 <- future3
} yield (r1+r2+r3)

誰かが私に<-このコードでは?ジェネレーターである場合、ループによって各要素をフェッチします。

55
nish1013

まず理解のために。 SOで何度も答えられました。これは、いくつかのモナド演算mapflatMapwithFilter。]に対する抽象化であると答えました。 _<-_を使用すると、scalacはこの行をモナドflatMapに脱糖します。

_r <- monad_ into monad.flatMap(r => ... )

それは命令型の計算のように見えます(モナドのすべて)、計算結果をrにバインドします。そして、yield部分はmap呼び出しに脱糖されます。結果のタイプは、monadのタイプに依存します。

FutureトレイトにはflatMapおよびmap関数があるため、理解に使用できます。あなたの例では、次のコードに脱糖できます:

_future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) )
_

並列処理はさておき

_future2_の実行が_r1_に依存する場合、シーケンシャル実行をエスケープできないことは言うまでもありませんが、将来の計算が独立している場合、2つの選択肢があります。順次実行、またはallowを並列実行に強制できます。実行コンテキストがこれを処理するので、enforce後者はできません。

_val res = for {
   r1 <- computationReturningFuture1(...)
   r2 <- computationReturningFuture2(...)
   r3 <- computationReturningFuture3(...)
} yield (r1+r2+r3)
_

常に連続して実行されます。脱糖によって簡単に説明できます。その後、後続のcomputationReturningFutureX呼び出しはflatMaps内でのみ呼び出されます。

_computationReturningFuture1(...).flatMap(r1 => 
    computationReturningFuture2(...).flatMap(r2 => 
        computationReturningFuture3(...).map(r3 => r1 + r2 + r3) ) )
_

ただし、これは並行して実行でき、理解のために結果が集約されます。

_val future1 = computationReturningFuture1(...)
val future2 = computationReturningFuture2(...)
val future3 = computationReturningFuture3(...)

val res = for {
   r1 <- future1
   r2 <- future2
   r3 <- future3
} yield (r1+r2+r3)
_
124
4lex1v

これらの既存の回答を詳しく説明するには、for内包表記がどのように機能するかを示す簡単な結果を示します。

少し長く機能しますが、見てみる価値はあります。

整数の範囲を与える関数

scala> def createIntegers = Future{
             println("INT "+ Thread.currentThread().getName+" Begin.")
             val returnValue = List.range(1, 256)
             println("INT "+ Thread.currentThread().getName+" End.")
             returnValue
         }
createIntegers: createIntegers: scala.concurrent.Future[List[Int]]

一連の文字を提供する関数

scala> def createAsciiChars = Future{
             println("CHAR "+ Thread.currentThread().getName+" Begin.")
             val returnValue = new ListBuffer[Char]
             for (i <- 1 to 256){
                  returnValue += i.toChar
             }
             println("CHAR "+ Thread.currentThread().getName+" End.")
             returnValue
          }
createAsciiChars: scala.concurrent.Future[scala.collection.mutable.ListBuffer[Char]]

これらの関数呼び出しを使用してwithinを理解します。

scala> val result = for{
                        i <- createIntegers
                        s <- createAsciiChars
                    } yield i.Zip(s)
       Await.result(result, Duration.Inf)
result: scala.concurrent.Future[List[(Int, Char)]] = Future(<not completed>)

以下の行では、すべての関数呼び出しが同期的であることがわかります。つまり、createAsciiChars関数呼び出しは、createIntegersが実行を完了するまで実行されないです。

scala> INT scala-execution-context-global-27 Begin.
       INT scala-execution-context-global-27 End.
       CHAR scala-execution-context-global-28 Begin.
       CHAR scala-execution-context-global-28 End.

これらの関数createAsciiCharscreateIntegers内包の外側のfor呼び出しは、非同期実行になります。

0
Puneeth Reddy V