Scala Language
Strömmar
Sök…
Anmärkningar
Strömmar utvärderas lata, vilket innebär att de kan användas för att implementera generatorer, som kommer att tillhandahålla eller "generera" en ny artikel av den angivna typen på begäran snarare än före faktum. Detta säkerställer att endast de beräkningar som krävs görs.
Använda en ström för att generera en slumpmässig sekvens
genRandom
skapar en ström av slumpmässiga nummer som har en av fyra chans att avsluta varje gång det heter.
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.
Observera #::
-konstruktionen, som latent återkommer : eftersom det förbereder det aktuella slumpmässiga numret till en ström, utvärderar den inte resten av strömmen förrän den är itererad igenom.
Oändliga strömmar via rekursion
Strömmar kan byggas som refererar till sig själva och blir därmed oändligt rekursiva.
// 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)
I detta sammanhang är skillnaden mellan Var, Val och Def intressant. Som def
beräknas varje element om varje gång det refereras. Som en val
behålls och återanvänds varje element efter att det har beräknats. Detta kan demonstreras genom att skapa en bieffekt med varje beräkning.
// 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
Detta förklarar också varför slumpmässigt antal Stream
inte fungerar som en val
.
val rndInt: Stream[Int] = (util.Random.nextInt(90)+10) #:: rndInt
rndInt.take(5) // (79, 79, 79, 79, 79)
Oändlig självreferensström
// 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, ?)")