Scala Language
Ruisseaux
Recherche…
Remarques
Les flux sont évalués avec précaution, ce qui signifie qu'ils peuvent être utilisés pour implémenter des générateurs, qui fourniront ou «généreront» un nouvel élément du type spécifié à la demande, plutôt qu'avant le fait. Cela garantit que seuls les calculs nécessaires sont effectués.
Utiliser un flux pour générer une séquence aléatoire
genRandom
crée un flux de nombres aléatoires qui a une chance sur quatre de se terminer à chaque appel.
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.
Notez la construction #::
qui récursivement paresseuse : comme elle ajoute le nombre aléatoire actuel à un flux, elle n'évalue pas le reste du flux jusqu'à ce qu'il soit itéré.
Flux infinis via la récursivité
On peut construire des flux qui se réfèrent eux-mêmes et deviennent ainsi infiniment récursifs.
// 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)
Dans ce contexte, la différence entre Var, Val et Def est intéressante. En tant que def
chaque élément est recalculé chaque fois qu'il est référencé. En tant que val
chaque élément est conservé et réutilisé après avoir été calculé. Cela peut être démontré en créant un effet secondaire à chaque calcul.
// 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
Cela explique également pourquoi le nombre aléatoire Stream
ne fonctionne pas comme un val
.
val rndInt: Stream[Int] = (util.Random.nextInt(90)+10) #:: rndInt
rndInt.take(5) // (79, 79, 79, 79, 79)
Flux infini d'auto-référence
// 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, ?)")