If you're learning Haskell, sooner or later you're going to run up against the concept of a monad. Probably sooner, since monads are how most IO is done in Haskell. To someone unfamiliar with both functional languages and the concept of a monad, this can be a sudden and daunting obstacle. This is too bad, because at its core the monad is not an intrinsically difficult concept. However, as with object oriented programming, it's the details, syntax, formal theory and other cruft of it that will destroy you.
So as a new Haskeller, I was pleased to run across this surprisingly readable paper on monads:
A little familiarity with functional programming is pretty much a requirement here. If my previous post on doing integer factorization in Haskell was a total impenetrable enigma to you, this paper is probably not your cup of tea. If, however, you are at least passingly familiar with functional languages and curious about these monad thingys that seem to play such a big part in higher level Haskell, you should definitely take a couple hours and read through this paper. I have read several web pages which advance the pretense that they are "tutorials" on monads. None of them come anywhere close to the clean, readily understandable simplicity of the first two chapters of this little PDF file.
I'll try and give you the short version, just to whet your appetite. A monad is sort of like a design pattern (a way of writing and thinking about functions) that allows functions in pure functional languages to incorporate side effects. This is a difficult problem, because normally the whole point of functional languages is that functions don't have side effects. However, side effects are very useful for several things: doing IO and handling program state principal among them. So, a monad is a mathematically rigorous way to allow functions to do extra computation "on the side" every time they're run. A way that fits perfectly into functional languages without breaking their basic structure. And how is this implemented? Well, the natural way in the context of functional programming - by adding additional arguments to the function. The arguments act as a container for the side effects, and certain rules apply to ensure that said side effects are applied consistently and predictably within the framework of the language.
Now if that sounds easy to you, then try and remember how tough it was to figure out all the complications surrounding objects, pointers and inheritance based only on first principles. There's nothing in the world so simple that it can't be made into a confusing mess with enough effort. And so it is with monads. The idea is simple. The implementation... not so much. But read the paper anyway. It's a far better foundation than you'll find anywhere else.