2011-10-03 20 views
6

Voglio usare IO monade.Scalaz's traverse_ con IO monad

Ma questo codice non funziona con file di grandi dimensioni. Ricevo un StackOverflowError. Ho provato l'opzione -DXss, ma genera lo stesso errore.

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

Come posso farlo?


Ho scritto Iteratee che restituisce tutti gli elementi.

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 

Questo è anche lo stesso risultato.

Penso che sia causato dall'implementazione IO.

+1

La prima domanda è: * perché/come * è non in esecuzione di un file di grandi dimensioni State ricevendo una errore di overflow dello stack, un errore di memoria esaurita o qualcos'altro? –

+1

Ricevo un errore StackOverflowError. Ho provato l'opzione -DXss, ma ho lanciato lo stesso errore. –

+0

D'accordo, penso che la monade IO aggiunga un po 'di sfida. – huynhjl

risposta

4

Questo perché scalac non sta ottimizzando loop all'interno di getReaderLines per chiamate di coda. loop è ricorsivo di coda ma penso che la sintassi della funzione anonima case si intrometta.

Modifica: in realtà non è nemmeno ricorsivo in coda (il wrapping nella monade IO) causa almeno un'altra chiamata dopo la chiamata ricorsiva. Quando stavo facendo i miei test ieri, stavo usando un codice simile, ma avevo abbandonato la monade IO ed è stato quindi possibile rendere ricorsiva la coda Iteratee. Il testo qui sotto, non presuppone alcun IO monade ...

Mi è capitato di scoprirlo ieri mentre sperimentavo con iterate. Credo che cambiando la firma del loop a questo vi aiuterà (quindi per il momento potrebbe essere necessario reimplementare getFilesLines e getReaderLines:

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

dovremmo probabilmente segnalarlo al popolare scalaz (e può essere aperto un biglietto di valorizzazione . per Scala)

Questo dimostra ciò che accade (codice di vagamente simile 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

Si prega di fare report in modo che possa essere migliorato! – AndreasScheinert