Я могу написать функцию обработки потока, drop(n,s)
, которая масштабируется до очень больших потоков. Но когда я пишу другую функцию, nth(n,s)
, которая принимает поток s
и перенаправляет его на drop(n,s)
, создается впечатление, что nth()
"держит голову" потока. Это приводит к OutOfMemoryError
для больших n
.
Вот код:
import scala.annotation.tailrec
import scala.collection.immutable.Stream.cons
object Streams {
def iterate[A](start: A, f: A => A): Stream[A] =
cons(start, iterate(f(start), f))
def inc(n:Int) = n + 1
def naturals() =
iterate(1, inc)
@tailrec def drop[T](n : Int, s : Stream[T]) : Stream[T] =
if (n <= 0 || s.isEmpty) s
else drop(n-1, s.tail)
// @inline didn't seem to help
def nth[T](n : Int, s : Stream[T]) =
drop(n,s).head
def N = 1e7.toInt
def main(args: Array[String]) {
println(drop(N,naturals()).head) // works fine for large N
println(nth(N, naturals())) // results in OutOfMemoryError for N set to 1e7.toInt and -Xmx10m
}
}
Мой опыт в этом вопросе Java: почему этот метод Java протекает - и почему встраивание в него исправляет утечку? приводит меня к мысли, что сгенерированный Scala код для nth()
не используется достаточно агрессивен при расчистке s
перед вызовом drop()
. Уловка библиотеки Clojure (уловка Java) (см. Связанный вопрос) здесь не работает, потому что все параметры функции Scala val
с (не var
с), поэтому их нельзя назначить (null
).
Как написать масштабируемое nth()
в терминах drop()
?
Вот связанная ошибка компилятора Scala 2009-2011 гг. (reduceLeft()
реализована в терминах foldLeft()
): https://issues.scala -lang.org / browse / SI-2239
Я не могу сказать из этого жучка Scala, как они это исправили. В билете было предложение, что единственный способ исправить это - дублировать код foldLeft()
в reduceLeft()
. Я действительно надеюсь, что это не ответ.
Обновление : ответ Андрея Тюкина https://stackoverflow.com/a/52209383/156550 исправляет это. Теперь у меня есть:
// have to call by name (s) here, otherwise we hold on to head!
def nth[T](n : Int, s : => Stream[T]) =
drop(n,s).head
И nth(n,s)
Масштаб отлично.