Вложенный ленивый для понимания - PullRequest
0 голосов
/ 24 марта 2012

У меня есть глубоко «вложенное» для понимания, упрощенное до 3 уровней ниже: x, y и z.Я надеялся, что только xa Stream сделает вычисления y и z ленивыми:

val stream = for {
  x <- List(1, 2, 3).toStream
  y <- List("foo", "bar", "baz")
  z = {
    println("Processed " + x + y)
    x + y
  }
} yield z

stream take (2) foreach (doSomething)

Но это вычисляет все 3 элемента, о чем свидетельствуют 3 отпечатка.Я бы хотел вычислить только первые 2, так как это все, что я взял из потока.Я могу обойти это, позвонив toStream на втором List и так далее.Есть ли лучший способ, чем называть это на каждом уровне понимания?

1 Ответ

3 голосов
/ 24 марта 2012

Он печатает:

Processed 1foo
Processed 1bar
Processed 1baz
stream: scala.collection.immutable.Stream[String] = Stream(1foo, ?)

scala> stream take (2) foreach (println)
1foo
1bar

Голова Stream всегда строго оценивается, поэтому вы видите Processed 1foo и т. Д., А не Processed 2foo и т. Д. Это печатается, когда высоздайте поток, или, точнее, при оценке заголовка stream.

Вы правы в том, что если вы хотите обрабатывать каждый результирующий элемент по одному, то все генераторы должны быть потоками.Вы можете обзвонить toStream, сделав их потоками для начала, как в примере ниже.

stream - это Stream[String], и его голова должна быть оценена.Если вы не хотите рассчитывать значение с нетерпением, вы можете либо добавить фиктивное значение, либо, что еще лучше, сделать его значением stream lazy:

lazy val stream = for {
  x <- Stream(1, 2, 3)
  y <- Stream("foo", "bar", "baz")
  z = { println("Processed " + x + y); x + y }
} yield z 

Этоне выполняйте никакой «обработки», пока не примете каждое значение:

scala> stream take 2 foreach println
Processed 1foo
1foo
Processed 1bar
1bar
...