Haskell interact function

A more reusable solution:

main = interactLineByLine processLine

-- this wrapper does the boring thing of mapping, unlining etc.... you have to do all the times for user interaction
interactLineByLine:: (String -> String) -> IO ()
interactLineByLine f = interact (unlines . (map processLine) . lines) 

-- this function does the actual work line by line, i.e. what is
-- really desired most of the times
processLine:: String -> String
processLine line = "<" ++ line ++ ">"

The String -> String argument given to interact should take a string containing all the input and return a string containing all the output. The reason you see output after pressing enter with interact (map toUpper) is because map toUpper acts lazily -- it can start giving output before all the input is known. Finding the length of a string is not like this -- the whole string must be known before any output can be produced.

You need to either signal an EOF to say that you are done entering input (in the console, this is Control-D on Unix/Mac systems, I believe it's Control-Z on Windows), then it will give you the length. Or you can find the length of each line by saying so:

interact (unlines . map inputLength . lines)

This will always be lazy in each line, so you know you can get one output after each input.

Since acting on lines is such a common pattern, I like to define a little helper function:

eachLine :: (String -> String) -> (String -> String)
eachLine f = unlines . map f . lines

Then you can do:

main = interact (eachLine inputLength)

Tags:

Haskell