6

I am trying to produce an interactive Haskell program using the interact function with map.

Here's what I get in ghci (as far as I can tell, that's the way all tutorials explain interact usage -- except the result).

*Module> interact $ unlines . map (++ "!") . lines
tteesstt
!

Note that what actually happens is that every character I type is instantly repeated and after I press Return the exclamation mark appears. I was, however, expecting this:

*Module> interact $ unlines . map (++ "!") . lines
test
test!

It works perfectly if I use the same program structure, but filter instead of map.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
notan3xit
  • 2,386
  • 2
  • 21
  • 26

2 Answers2

10

The problem is that ghci changes the buffering mode to per-character. This is, that the program starts to process the code as soon as it is there. If you write this line into a file called foo.hs

main = interact $ unlines . map (++ "!") . lines

and run it using runhaskell foo.hs you will see that it works as expected, because Haskell uses line-buffering by default.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • 1
    Thank you, this is perfectly correct. It is possible to set it to line buffering by executing `import IO` and then `hSetBuffering stdout LineBuffering`. – notan3xit May 31 '11 at 17:01
3

As FUZxxl says, it's a buffering issue.

To change buffering styles in GHCi, use hSetBuffering

Prelude> :m +System.IO
Prelude System.IO> hSetBuffering stdout LineBuffering 
Prelude System.IO> interact $ unlines . map (++"!") . lines
hello
hello!
^CInterrupted.
Prelude System.IO> 
rampion
  • 87,131
  • 49
  • 199
  • 315