Scalaz traverse_ with monk IO

I want to use IO monad.

But this code does not start with a large file. I get a StackOverflowError. I tried the -DXss , but it throws the same error.

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

How can i do this?


I wrote Iteratee, which displays the whole element.

 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 

This is also the same result.

I think this is due to the implementation of IO.

+6
source share
1 answer

This is because scalac does not optimize the loop inside getReaderLines for tail calls. loop is tail recursive, but I think the syntax of case anonymous functions gets in the way.

Edit : this is actually not even tail recursion (a wrapper in the IO monad) causes at least one more call after a recursive call. When I tested my testing yesterday, I used the same code, but I dropped the IO monad, and then it was possible to make a Iteratee reverse tail. The text below suggests that IO monad ...

I accidentally discovered this yesterday while experimenting with iterations. I think changing the loop signature to this will help (so for now you have to override getFilesLines and getReaderLines :

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

We should probably report this to the scalaz community (and an expansion ticket for scala may be open).

This shows what is happening (the code is vaguely similar to 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 = { ^ */ 
+4
source

Source: https://habr.com/ru/post/898506/


All Articles