Suche…


Bemerkungen

Streams werden faul bewertet, dh sie können zur Implementierung von Generatoren verwendet werden, die auf Abruf ein neues Element des angegebenen Typs bereitstellen oder "erzeugen" und nicht vor der Tatsache. Dadurch wird sichergestellt, dass nur die erforderlichen Berechnungen ausgeführt werden.

Verwenden eines Streams zum Erzeugen einer zufälligen Sequenz

genRandom erstellt einen Stream von Zufallszahlen, der bei jedem genRandom eine Chance von eins zu vier hat.

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.

Beachten Sie das #:: -Konstrukt , das langsam rekonstruiert : Da es die aktuelle Zufallszahl einem Stream voranstellt, wertet es den Rest des Streams nicht aus, bis er durchlaufen wird.

Unendliche Streams über Rekursion

Streams können aufgebaut werden, die sich selbst referenzieren und somit unendlich rekursiv werden.

// 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)

In diesem Zusammenhang ist der Unterschied zwischen Var, Val und Def interessant. Als def jedes Element jedes Mal neu berechnet, wenn es referenziert wird. Als val jedes Element beibehalten und wiederverwendet, nachdem es berechnet wurde. Dies kann demonstriert werden, indem bei jeder Berechnung ein Nebeneffekt erstellt wird.

// 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

Dies erklärt auch , warum die Zufallszahl - Stream nicht als Arbeit val .

val rndInt: Stream[Int] = (util.Random.nextInt(90)+10) #:: rndInt
rndInt.take(5)  // (79, 79, 79, 79, 79)

Unendlich selbstreferenzierender Stream

// 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow