| Prev: The List monad | TOC: Contents | Next: The State monad |
| Computation type: | Computations which perform I/O |
|---|---|
| Binding strategy: | I/O actions are executed in the order in which they are bound. Failures throw I/O errors which can be caught and handled. |
| Useful for: | Performing I/O within a Haskell program. |
| Zero and plus: | None. |
| Example type: | IO a |
Input/Output is incompatible with a pure functional language because it is not referentially transparent and side-effect free. The IO monad solves this problem by confining computations that perform I/O within the IO monad.
The definition of the IO monad is platform-specific. No data constructors are exported and no functions are provided to remove data from the IO monad. This makes the IO monad a one-way monad and is essential to ensuring safety of functional programs by isolating side-effects and non-referentially transparent actions within the imperative-style computations of the IO monad.
Throughout this tutorial, we have referred to monadic values as computations. However, values in the IO monad are often called I/O actions and we will use that terminology here.
In Haskell, the top-level main function must have
type IO (), so that programs are typically
structured at the top level as an imperative-style sequence of I/O
actions and calls to functional-style code. The functions exported
from the IO module do not perform I/O themselves.
They return I/O actions, which describe an I/O operation to
be performed. The I/O actions are combined within the IO monad (in a purely
functional manner) to create more complex I/O actions, resulting in the final
I/O action that is the main value of the program.
The standard prelude and the
IO module
define many functions that can be used within the IO monad and
any Haskell programmer will undoubtedly be familiar with some of them.
This tutorial will only discuss the monadic aspects of the IO monad,
not the full range of functions available to perform I/O.
The IO type constructor is a member of the Monad
class and the MonadError class, where errors are of the type
IOError. fail is defined to throw an error built
from the string argument. Within the IO monad you can use
the exception mechanisms from the Control.Monad.Error module
in the Monad Template Library if you import the module. The same mechanisms
have alternative names exported by the IO module: ioError
and catch.
instance Monad IO where
return a = ... -- function from a -> IO a
m >>= k = ... -- executes the I/O action m and binds the value to k's input
fail s = ioError (userError s)
data IOError = ...
ioError :: IOError -> IO a
ioError = ...
userError :: String -> IOError
userError = ...
catch :: IO a -> (IOError -> IO a) -> IO a
catch = ...
try :: IO a -> IO (Either IOError a)
try f = catch (do r <- f
return (Right r))
(return . Left)
|
The IO monad is incorporated into the Monad Template
Library framework as an instance of the MonadError class.
instance Error IOError where
...
instance MonadError IO where
throwError = ioError
catchError = catch
|
The IO module exports a convenience function called
try that executes an I/O action and returns
Right result if the action succeeded or
Left IOError if an I/O error was caught.
This example shows a partial implementation of the "tr" command that
copies the standard input stream to the standard output stream with
character translations controlled by command-line arguments. It
demonstrates the use of the exception handling mechanisms of the
MonadError class with the IO monad.
| Code available in example14.hs |
|---|
import Monad
import System
import IO
import Control.Monad.Error
-- translate char in set1 to corresponding char in set2
translate :: String -> String -> Char -> Char
translate [] _ c = c
translate (x:xs) [] c = if x == c then ' ' else translate xs [] c
translate (x:xs) [y] c = if x == c then y else translate xs [y] c
translate (x:xs) (y:ys) c = if x == c then y else translate xs ys c
-- translate an entire string
translateString :: String -> String -> String -> String
translateString set1 set2 str = map (translate set1 set2) str
usage :: IOError -> IO ()
usage e = do putStrLn "Usage: ex14 set1 set2"
putStrLn "Translates characters in set1 on stdin to the corresponding"
putStrLn "characters from set2 and writes the translation to stdout."
-- translates stdin to stdout based on commandline arguments
main :: IO ()
main = (do [set1,set2] <- getArgs
contents <- hGetContents stdin
putStr $ translateString set1 set2 contents)
`catchError` usage
|
| Prev: The List monad | TOC: Contents | Next: The State monad |