Обход потока памяти с эффективным использованием памяти с использованием класса типов скалаза Traverse

Я пытаюсь пройти / упорядочить большой поток (например, scala.collection.immutable.Stream) используя Scalaz' (версия 7.1.2) Traverse класс, но я постоянно сталкиваюсь с java.lang.OutOfMemoryError: GC overhead limit exceeded вопрос.

Мой обход выглядит примерно так:

import scalaz._
import Scalaz._
import scala.collection.immutable.Stream

Stream.range(1, 1000000000).traverse[MTrans, Int](f)

где MTrans это монадный трансформатор, включающий EitherT а также StateT а также f: Int => MTrans[Int],

Я вообще просто заинтересован в последовательности элементов (передача состояния) и нужен только конечный результат (MTrans[Int]), а не вся (материализованная) последовательность / поток.

У меня есть версии с traverseKTrampoline но это не помогает, так как это не StackruError выпускать как описано в других подобных постах. Я также пробовал сочетания использования EphemeralStream а также sequence но не имели успеха.

Как я могу (память-) эффективно пройти / упорядочить такой поток?

Обновление 1

Ниже приведен более полный пример того, что я пытаюсь сделать. Это близко напоминает структуру, которая у меня есть, и демонстрирует ту же проблему (предел нагрузки GC в какой-то момент превышает).

object Main {

  import scalaz._
  import Scalaz._
  import Kleisli._

  import scala.collection.immutable.Stream

  import scala.language.higherKinds

  case class IState(s: Int)

  type IStateT[A] = StateT[Id, IState, A]
  type MTransT[S[_], A] = EitherT[S, String, A]
  type MTrans[A] = MTransT[IStateT, A]

  def eval(k: Int): MTrans[Int] = {
    for {
      state <- get[IState].liftM[MTransT]
      _ <- put(state.copy(s = state.s % k)).liftM[MTransT]
    } yield (k + 1)
  }

  def process(i: Int, k: Int): MTrans[Int] = {
    for {
      state <- get[IState].liftM[MTransT]
      _ <- put(state.copy(s = state.s + i)).liftM[MTransT]
      res <- eval(k)
    } yield res
  }

  def run() = {
    val m = Stream
      .range(1, 1000000000)
      .traverseKTrampoline[MTrans, Int, Int](i => kleisli(process(i, _))).run(7)

    m.run(IState(0))
  }
}

Обновление 2

На основании некоторого вклада Эрика и от Applicative против монадических комбинаторов и свободной монады в Scalaz, я придумал следующее простое foldLeftрешение на основе аппликативного *>:

val m = Stream
  .range(1, 1000000000)
  .toEphemeralStream
  .foldLeft(0.point[MTrans]) { acc => i =>
    acc *> process(i, 3)
}

Хотя это (все еще) кажется безопасным для стека, оно требует большого количества кучи и работает очень медленно.

0 ответов

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