interact is a very handy function, but it doesn’t handle computations that can fail. Here’s another convenience function that addresses that:

import System.IO
import System.Exit

interactEither :: Show a => (String -> Either a String) -> IO ()
interactEither  f = getContents >>= either (error . show) success . f
  where success x = hPutStrLn stdout x >> exitSuccess
        error   x = hPutStrLn stderr x >> exitFailure