[Haskell-cafe] so how does one convert an IO a into an a ?
Alastair Reid
alastair at reid-consulting-uk.ltd.uk
Thu Jul 8 18:19:39 EDT 2004
> [...]
> So I am still in IO Int land despite having used the >>= in the do syntax.
> [...]
The idea of the IO type is that it marks code that can behave differently each
time it is called. For this reason, the IO monad 'infects' everything above
it in the call chain and, for this reason, the entire program (i.e.,
Main.main) has type IO ().
Rather than trying to extract an Int from the IO monad, you should look at how
you can use an Int inside the IO monad. Many programs have a structure like
this: read a value, compute a result, display the result. Let's suppose we
have a function to do each of these three parts:
readValue :: IO Int
compute :: Int -> String
display :: String -> IO ()
Note that reading and displaying have side effects and/or depend on the
environment so they involve the IO monad.
Since they involve a monad, let's use the do notation. Obviously, we start by
reading a value:
main = do
x <- readValue
....
The next thing to do is to compute a result. From the types, we know that x
has type Int so obviously we want something involving 'compute x'. compute
is not in the IO monad so we'll use a let binding instead of '<-':
main = do
x <- readValue
let y = compute x
...
Now we want to display y. We know that y has type String so we can apply
display to it. 'display y' has type 'IO ()' so we use a monadic binding (<-)
instead of a let binding:
main = do
x <- readValue
let y = compute x
z <- display y
....
Hmmm, what to do with z. It's type is just () so we don't really need to bind
it to anything so let's drop the binding to get the complete program:
main = do
x <- readValue
let y = compute x
display y
Let me summarise what went on here:
1) If something has monadic type (i.e., has side effects or depends
on the environment it is run in), use '<-' to bind the (non-monadic)
result to a variable.
2) If something is not monadic (i.e., doesn't affect the world and
doesn't depend on the world), use 'let' to bind the (non-monadic)
result to a variable.
3) If something has a monadic type but we don't care about the result
(so, presumably, it has an interesting side effect) you can drop
the 'blah <-' part.
[This last rule makes more sense if you use >>= and >> instead of the
do notation. >>= corresponds to binding a result using '<-' while
>> corresponds to not binding a result.]
Another way of looking at it is that the IO monad infects the type of
everything _above_ it in the call chain but doesn't infect the type of things
_below_ it. So if you have a pure function like 'compute', you just call it
from within the IO monad rather than trying to get out of the IO monad, call
compute and then go back into the IO monad when you want to display the
result.
I hope this helps,
--
Alastair Reid
More information about the Haskell-Cafe
mailing list