Haskell requires an explicit type for operations involving input
and output. This way it makes a problem explicit, that exists in
every language: Input and output functions can have so many
effects, that the type signature says more or less that almost
everything must be expected. It is hard to test them, because
they can in principle depend on every state of the real world.
Thus in order to maintain modularity you should avoid IO
whereever possible.It is too tempting to get rid of IO by but we
want to present some clean techniques to avoid IO. You can avoid
a series of output functions by constructing a complex data
structure with non-IO code and output it with one output
function. -- import Control.Monad (replicateM_) replicateM_ 10
(putStr "foo") putStr (concat $ replicate 10 "foo") do h <-
openFile "foo" WriteMode replicateM_ 10 (hPutStr h "bar") hClose
h can be shortened to writeFile "foo" (concat $ replicate 10
"bar") in case of failure. Since you have now an expression for
the complete result as string