Когда ленивые для Скалы ленивы? - PullRequest
13 голосов
/ 09 августа 2011

В Python я могу сделать что-то вроде этого:

lazy = ((i,j) for i in range(0,10000) for j in range(0,10000))
sum((1 for i in lazy))

Это займет некоторое время, но использование памяти будет постоянным.

Та же самая конструкция в scala:

(for(i<-0 to 10000; j<-i+1 to 10000) yield (i,j)).count((a:(Int,Int)) => true)

Через некоторое время я получаю java.lang.OutOfMemoryError, хотя его следует оценивать лениво.

Ответы [ 2 ]

22 голосов
/ 09 августа 2011

Нет ничего ленивого в понимании Скалы;это синтаксический сахар *, который не изменит тот факт, что комбинация ваших двух диапазонов будет нетерпеливой.

Если вы работаете с ленивыми 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)))
12 голосов
/ 09 августа 2011

Лень исходит не из-за понимания, а из самой коллекции.Вы должны взглянуть на характеристики строгости коллекции.

Но, для ленивых :-), вот краткое изложение: Iterator и Stream не являются строгими, как и выбранные методы view из любой коллекции.Так что, если вы хотите лени, обязательно .iterator, .view или .toStream вашей коллекции в первую очередь.

...