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, ?)")


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow