Scala Language
ストリーム
サーチ…
備考
ストリームは遅延評価され、ジェネレータを実装するために使用できることを意味します。ジェネレータは、事実の前にではなく、指定されたタイプの新しいアイテムをオンデマンドで提供または生成します。これにより、必要な計算だけが確実に行われます。
ストリームを使用したランダムシーケンスの生成
genRandom
は、呼び出されるたびに終了する確率が4分の1の乱数ストリームを作成します。
def genRandom: Stream[String] = {
val random = scala.util.Random.nextFloat()
println(s"Random value is: $random")
if (random < 0.25) {
Stream.empty[String]
} else {
("%.3f : A random number" format random) #:: genRandom
}
}
lazy val randos = genRandom // getRandom is lazily evaluated as randos is iterated through
for {
x <- randos
} println(x) // The number of times this prints is effectively randomized.
lazily recursesである#::
構造体に注意してください。これは、現在の乱数をストリームに付加するため、反復処理されるまでストリームの残りの部分を評価しません。
再帰による無限ストリーム
ストリーム自体を参照して無限に再帰的になるストリームを構築することができます。
// factorial
val fact: Stream[BigInt] = 1 #:: fact.zipWithIndex.map{case (p,x)=>p*(x+1)}
fact.take(10) // (1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880)
fact(24) // 620448401733239439360000
// the Fibonacci series
val fib: Stream[BigInt] = 0 #:: fib.scan(1:BigInt)(_+_)
fib.take(10) // (0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
fib(124) // 36726740705505779255899443
// random Ints between 10 and 99 (inclusive)
def rndInt: Stream[Int] = (util.Random.nextInt(90)+10) #:: rndInt
rndInt.take(10) // (20, 95, 14, 44, 42, 78, 85, 24, 99, 85)
この文脈では、 Var、Val、Defの違いは興味深い。 def
として、各要素は参照されるたびに再計算されます。 val
として各要素は保持され、計算された後に再利用されます。これは、各計算で副作用を作成することで実証できます。
// def with extra output per calculation
def fact: Stream[Int] = 1 #:: fact.zipWithIndex.map{case (p,x)=>print("!");p*(x+1)}
fact(5) // !!!!!!!!!!!!!!! 120
fact(4) // !!!!!!!!!! 24
fact(7) // !!!!!!!!!!!!!!!!!!!!!!!!!!!! 5040
// now as val
val fact: Stream[Int] = 1 #:: fact.zipWithIndex.map{case (p,x)=>print("!");p*(x+1)}
fact(5) // !!!!! 120
fact(4) // 24
fact(7) // !! 5040
これは、なぜ乱数Stream
がval
として機能しないのかを説明します。
val rndInt: Stream[Int] = (util.Random.nextInt(90)+10) #:: rndInt
rndInt.take(5) // (79, 79, 79, 79, 79)
無限の自己参照ストリーム
// Generate stream that references itself in its evaluation lazy val primes: Stream[Int] = 2 #:: Stream.from(3, 2) .filter { i => primes.takeWhile(p => p * p <= i).forall(i % _ != 0) } .takeWhile(_ > 0) // prevent overflowing // Get list of 10 primes assert(primes.take(10).toList == List(2, 3, 5, 7, 11, 13, 17, 19, 23, 29)) // Previously calculated values were memoized, as shown by toString assert(primes.toString == "Stream(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ?)")
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow