2017-12-15 11 views
1

私は最近、複数のストリームを反復処理することで、最初のアイテムだけを反復するという、自分のコードのバグに遭遇しました。ストリームをバッファに変換しました(呼び出す関数の実装がストリームを返すことに気づいていなかった)問題が修正されました。私は信じて、このハード見つかったので、私は最小の検証例を作成した:なぜ複数のストリームを反復処理するのが最初の要素に対してのみ反復処理を行うのですか?

def f(as: Seq[String], bs: Seq[String]): Unit = 
    for { 
     a <- as 
     b <- bs 
    } yield println((a, b)) 

    val seq = Seq(1, 2, 3).map(_.toString) 
    f(seq, seq) 

    println() 

    val stream = Stream.iterate(1)(_ + 1).map(_.toString).take(3) 
    f(stream, stream) 

その入力のすべての組み合わせを印刷し、そして配列で呼び出される関数[1、2、3]、ストリーム[1 、2,3]。

配列との結果は次のとおりです。

(1,1) 
(1,2) 
(1,3) 
(2,1) 
(2,2) 
(2,3) 
(3,1) 
(3,2) 
(3,3) 

とストリームとの結果は次のとおりです。

(1,1) 

私だけを反復処理する、複数の発電機を反復処理する際に、これを複製することができました単一のストリームが正常に動作するようです。

私の質問は次のとおりです:なぜこれが起こるのですか?このようなグリッチを避けるにはどうしたらいいですか?つまり、すべてのマルチジェネレータ反復の前に.toBufferまたは.to[Vector]を使用するのに不足していますか?

ありがとうございました。

答えて

2

for-comprehension(yieldでprintln)を使用している方法はちょっと変わっていて、あなたがしたいことではないかもしれません。実際にエントリをプリントアウトしたい場合は、foreachを使用してください。これは、Streamのような怠惰なシーケンスを強制する、すなわち

def f_strict(as: Seq[String], bs: Seq[String]): Unit = { 
    for { 
    a <- as 
    b <- bs 
    } println((a, b)) 
} 

あなたfとの奇妙な行動を取得している理由はStreamsは怠惰であり、必要に応じて要素のみを計算し(その後、メモ化)されていることです。 fによって作成されたStreamを絶対に使用しないため(必ずfUnitを返すため)、頭だけが計算されます(これは単一の(1, 1)を表示している理由です)。 (タイプSeq[Unit]を持っている)、すなわち

def f_new(as: Seq[String], bs: Seq[String]): Seq[Unit] = { 
    for { 
    a <- as 
    b <- bs 
    } yield println((a, b)) 
} 

次にあなたがうまくいけば、何が起こっているのか解明するのに役立つはず、次の動作を取得します:

val xs = Stream(1, 2, 3) 
val result = f_new(xs.map(_.toString), xs.map(_.toString)) 
//prints out (1, 1) as a result of evaluating the head of the resulting Stream 
result.foreach(aUnit => {}) 
//prints out the other elements as the rest of the entries of Stream are computed, i.e. 
//(1,2) 
//(1,3) 
//(2,1) 
//... 
result.foreach(aUnit => {}) 
//probably won't print out anything because elements of Stream have been computed, 
//memoized and probably don't need to be computed again at this point. 
+0

mind.setIsBlown(真) – Phoenix

+0

は 'を省略利回りは正確に私が何d idは 'f_strict'です。 –

+0

どのように私はそれを逃したのですか? – Phoenix