Deep confusion about monads

Mark Carroll mark@chaos.x-philes.com
Thu, 16 Aug 2001 16:30:48 -0400 (EDT)


Let me know if I'm bugging you guys too much. It'd be great if I had
someone close at hand who knew more about Haskell than I do, but
unfortunately I don't. Are there any fora that are especially for people
to help novices, or is haskell-cafe the best fit?

I decided I ought to learn more about monads, so I've been trying to do
simple IO. However, I'm running into really basic problems that I haven't
managed to solve with the three monad tutorials I've read so far!

First, given an IO String, I don't seem to be able to take the head of it
to get an IO Char. I'm guessing that the IO monad is quite unlike the
simple 'tainting' I first imagined; I reall do seem to have to treat it as
an abstract polymorphic type. Worse, I can't work out how to write a IO
String -> IO Char version of head; I can't make my (x:xs) match an IO
String! Better would be if I could somehow write an IO String -> IO Char
wrapper for head.

I'm also confused as to why I can write:

readFile "/tmp/foo" >>= putStr

to print out the contents of a file but, in ghci,

let x = readFile "/tmp/foo"
putStr x

...doesn't work. Then again, I'm also confused by the way that Simon
Thompson's book says that,

(>>=) :: IO a -> (a -> IO a) -> IO a

which I think might be a misprint for,

(>>=) :: IO a -> (a -> IO b) -> IO b

...?

I'm not sure if I've explained enough of my confusion that a succinct,
helpful response not mentioned in what I've read so far can be easily
given. I guess that my problem is that I had initially imagined that the
prefix 'IO' appears as a magical tainting of any data that could depend on
the result of some IO action. However, I'm coming to the conclusion that
I'm quite wrong in this. I'd like to be able to manipulate IO Strings as
if they were just strings that I can't forget came from IO, but I'm
guessing now that things aren't that simple - they really are quite
different to strings, yet I want to avoid resorting to unsafePerformIO.
The really annoying thing is that all the monad examples I've read so far
have made perfect sense to me. (-: What I'm really hoping is that a simple
answer as to how best to arrange my IO String -> IO Char (or IO [a] -> IO
a) version of head will somehow resolve a lot of my confusion. For
instance, maybe I have to somehow write an 'action' version of head that I
apply with the help of >>= ?

-- Mark