"interact" behaves oddly if used interactively

Marc A. Ziegert coeus at gmx.de
Wed Oct 1 13:53:20 EDT 2003

> "main=interact id" basically echoes every line of my input, whereas
> "main=interact show" correctly waits for EOF before outputting something.

> What should a student think about "interact" in the Prelude? (It's ok 
> for pipes only, I guess.)

main = interact show
behaves similar to
main = interact (\x->seq (length x) x)

i do not know the exact implementation, but i think of it like ...

import System.IO        (hGetContents,hIsEOF,hGetChar,stdin)
import System.IO.Unsafe (unsafePerformIO)

interact :: (String -> String) -> IO ()
interact f = do s <- hGetContents stdin
                putStr $ f s

putStr = mapM_ putChar

hGetContents h = do eof <- hIsEOF h
                    if eof then return []
                           else c <- hGetChar h
                                return (c : (unsafePerformIO $ hGetContents h))

... so there will be the same problems like with getChar, hGetChar, getLine, or hGetLine (buffering), and with hGetContents and unsafePerformIO (sequrence of IOs).

for beginners/students: think about such situations: (to me, it was the reason to learn IO monadic programming)
read the next char(s) from input before writing the previous char(s) to output.

f :: String -> String
f [] = []
f (c:[]) = (c:[])
f (c:s) = (c:f s)

equals to

f :: String -> String
f [] = []
f (c:[]) = (c:[])
f (prev:s@(next:_)) = (prev:f s)

More information about the Haskell mailing list