Когда ленивые для Скалы ленивы?

В 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 Ваша коллекция первой.

Другие вопросы по тегам