Scala, Erastothenes: есть ли простой способ заменить поток итерацией?

Я написал функцию, которая генерирует простые числа бесконечно (википедия:инкрементальное сито эрастотена) использование потоков. Он возвращает поток, но он также объединяет потоки простых кратных внутри, чтобы пометить предстоящие композиты. Определение является кратким, функциональным, элегантным и простым для понимания, если я так скажу:

def primes(): Stream[Int] = {
  def merge(a: Stream[Int], b: Stream[Int]): Stream[Int] = {
    def next = a.head min b.head
    Stream.cons(next, merge(if (a.head == next) a.tail else a,
                            if (b.head == next) b.tail else b))
  }
  def test(n: Int, compositeStream: Stream[Int]): Stream[Int] = {
    if (n == compositeStream.head) test(n+1, compositeStream.tail)
    else Stream.cons(n, test(n+1, merge(compositeStream, Stream.from(n*n, n))))
  }
  test(2, Stream.from(4, 2))
}

Но я получаюjava.lang.OutOfMemoryError: Превышен лимит накладных расходов GC " когда я пытаюсь сгенерировать 1000-е простое число.

У меня есть альтернативное решение, которое возвращает итератор над простыми числами и использует внутреннюю очередь приоритетов кортежей (множественное число, простое число, используемое для генерации множественного числа), чтобы пометить предстоящие композиции. Он работает хорошо, но занимает примерно вдвое больше кода, и мне пришлось перезапустить его с нуля:

import scala.collection.mutable.PriorityQueue
def primes(): Iterator[Int] = {
  // Tuple (composite, prime) is used to generate a primes multiples
  object CompositeGeneratorOrdering extends Ordering[(Long, Int)] {
    def compare(a: (Long, Int), b: (Long, Int)) = b._1 compare a._1
  }
  var n = 2;
  val composites = PriorityQueue(((n*n).toLong, n))(CompositeGeneratorOrdering)
  def advance = {
    while (n == composites.head._1) { // n is composite
      while (n == composites.head._1) { // duplicate composites
        val (multiple, prime) = composites.dequeue
        composites.enqueue((multiple + prime, prime))
      }
      n += 1
    }
    assert(n < composites.head._1)
    val prime = n
    n += 1
    composites.enqueue((prime.toLong * prime.toLong, prime))
    prime
  }
  Iterator.continually(advance)
}

Есть ли простой способ перевести код с потоками в код с итераторами? Или есть простой способ сделать мою первую попытку более эффективной памяти?

Это'проще мыслить в терминах потоков; Я'Я предпочел бы начать таким образом, а затем настроить мой код, если это необходимо.

Ответы на вопрос(4)

Ваш ответ на вопрос