This is a bug in the definition of getReaderLines
. Compare the current version:
/** Enumerate the lines from a BufferedReader */
def getReaderLines(r: => BufferedReader): EnumeratorM[IO, String] =
new EnumeratorM[IO, String] {
def apply[A](it: IterV[String, A]) = {
def loop(i: IterV[String, A]): IO[IterV[String, A]] = i.fold(
done = (_,_) => io { i },
cont = k => for {
s <- rReadLn(r)
a <- s.map(l => loop(k(El(l)))).getOrElse(io(i))
} yield a
)
loop(it)
}
}
With one that works:
/** Enumerate the lines from a BufferedReader */
def getReaderLines(r: => BufferedReader): EnumeratorM[IO, String] =
new EnumeratorM[IO, String] {
lazy val reader = r
def apply[A](it: IterV[String, A]) = {
def loop(i: IterV[String, A]): IO[IterV[String, A]] = i.fold(
done = (_,_) => io { i },
cont = k => for {
s <- rReadLn(reader)
a <- s.map(l => loop(k(El(l)))).getOrElse(io(i))
} yield a
)
loop(it)
}
}
The issue is that r
is a by-name parameter, which means that given the way that getLines
is defined, the current version creates a new reader wrapping standard input on every loop.
Until this gets fixed in the library (and I doubt there'll be much of a rush to get 6.0.5 out the door), the simplest fix is to write your own getLines
:
val getLines: EnumeratorM[IO, String] = {
val r = new BufferedReader(new InputStreamReader(System.in))
getReaderLines(r)
}
This will work as expected.