2011-10-03 28 views
6

Quiero usar la mónada IO.Traverse_ de Scalaz con IO monad

Pero este código no se ejecuta con un archivo grande. Obtengo un StackOverflowError. Probé la opción -DXss, pero arroja el mismo error.

val main = for { 
    l <- getFileLines(file)(collect[String, List]).map(_.run) 
    _ <- l.traverse_(putStrLn) 
} yield() 

¿Cómo puedo hacerlo?


Escribí Iteratee que muestra todos los elementos.

def putStrLn[E: Show]: IterV[E, IO[Unit]] = { 
    import IterV._ 
    def step(i: IO[Unit])(input: Input[E]): IterV[E, IO[Unit]] = 
    input(el = e => Cont(step(i >|> effects.putStrLn(e.shows))), 
     empty = Cont(step(i)), 
      eof = Done(i, EOF[E])) 
    Cont(step(mzero[IO[Unit]])) 
} 
val main = for { 
    i <- getFileLines(file)(putStrLn).map(_.run) 
} yield i.unsafePerformIO 

Este es también el mismo resultado.

Creo que se debe a la implementación de IO.

+1

La primera pregunta es por qué */* cómo es que no ejecuta con un archivo grande ¿usted está consiguiendo una ¿hay un error de desbordamiento de la pila, un error de falta de memoria o alguna otra cosa? –

+1

Obtengo un StackOverflowError. Intenté la opción -DXss, pero arrojé el mismo error. –

+0

De acuerdo, creo que la mónada IO agrega un poco de desafío. – huynhjl

Respuesta

4

Esto se debe a scalac no está optimizando loop dentro getReaderLines para las llamadas de cola. loop es cola recursiva, pero creo que la sintaxis de la función anónima case se interpone en el camino.

Editar: en realidad, ni siquiera es cola recursiva (la envoltura en la mónada IO) causa al menos una llamada más después de la llamada recursiva. Cuando estaba haciendo mis pruebas ayer, estaba usando un código similar, pero había descartado la mónada IO y era posible hacer que la cola Iteratee fuera recursiva. El texto a continuación, asume que no hay una mónada de IO ...

Me enteré ayer cuando experimenté con iteratees. Creo que el cambio de la firma de loop a que esto ayudará (por lo que por el momento, es posible que tenga que volver a implementar getFilesLines y getReaderLines:

@annotations.tailrec 
def loop(it: IterV[String, A]): IO[IterV[String, A]] = it match { 
    // ... 
} 

probablemente deberíamos informar de esto a la gente scalaz (y puede estar abierto un billete de mejora . de Scala)

Esto muestra lo que sucede (código vagamente similar a getReaderLines.loop):?

@annotation.tailrec 
def f(i: Int): Int = i match { 
    case 0 => 0 
    case x => f(x - 1) 
} 
// f: (i: Int)Int 

@annotation.tailrec 
def g: Int => Int = { 
    case 0 => 0 
    case x => g(x - 1) 
} 
/* error: could not optimize @tailrec annotated method g: 
it contains a recursive call not in tail position 
     def g: Int => Int = { 
         ^
*/ 
+0

¡Por favor informe para que se pueda mejorar! – AndreasScheinert