Когда ленивые для Скалы ленивы?
В Python я могу сделать что-то вроде этого:
lazy = ((i,j) for i in range(0,10000) for j in range(0,10000))
sum((1 for i in lazy))
Это займет некоторое время, но использование памяти постоянно.
Та же самая конструкция в скале:
(for(i<-0 to 10000; j<-i+1 to 10000) yield (i,j)).count((a:(Int,Int)) => true)
Через некоторое время я получаю java.lang.OutOfMemoryError
хотя это стоит оценивать лениво.
2 ответа
Нет ничего ленивого в понимании Скалы; это синтаксический сахар *, который не изменит тот факт, что комбинация ваших двух диапазонов будет нетерпеливой.
Если вы работаете с ленивым view
Из ваших диапазонов результат понимания тоже будет ленивым:
scala> for(i<-(0 to 10000).view; j<-(i+1 to 10000).view) yield (i,j)
res0: scala.collection.SeqView[(Int, Int),Seq[_]] = SeqViewN(...)
scala> res0.count((a: (Int, Int)) => true)
res1: Int = 50005000
Лень здесь не имеет ничего общего с пониманием, а потому, что когда flatMap
или же map
(см. ниже) вызывается для некоторого типа контейнера, вы получаете результат в том же типе контейнера. Таким образом, для понимания просто сохранится лень (или нехватка) всего, что вы вкладываете.
* для чего-то вроде:
(0 to 10000).flatMap(i => (i+1 to 10000).map(j => (i, j)))
Лень исходит не из-за понимания, а из самой коллекции. Вы должны посмотреть на характеристики строгости коллекции.
Но, для ленивых:-), вот резюме: Iterator
а также Stream
не являются строгими, так как выбранные методы view
любой коллекции. Итак, если вы хотите лени, обязательно .iterator
, .view
или же .toStream
Ваша коллекция первой.