"They're a necessary workaround to do some stuff in pure functional languages"
This isn't actually true. You can still write imperative programs in a pure FP language. The most obvious way is to write your code in continuation passing style and pass the new state of the world to each continuation; taking the implicit state changes of an imperative language and making them explicit.
The real reason for using monads is that the scheme I just described is inhumanly complicated. Monads are a much more structured way of doing the same thing. Instead of writing these state passing CPS functions, you write functions that build them for you. A consequence of this is that monads perform much the same function as macros in Lisp; they are programs that build programs.
Agreed. I guess I should have added, "without making things unnecessarily complicated.".
I think that monads, too, are generally presented in a way that makes them more complicated than they really are. (Hence, I suppose, SPJ's comment about how they should have been called "warm fuzzy things".) Part of my trouble understanding them confronting the basics of Haskell at the same time, and I (along with much of what I read) focused on the IO monad. That's probably one of the most complicated ones. The ideas started to click when I switched to the Maybe monad -- not only is that one considerably more straightforward, but I (and probably many others) had already written essentially the same construct elsewhere, albeit without the formal notation.
This isn't actually true. You can still write imperative programs in a pure FP language. The most obvious way is to write your code in continuation passing style and pass the new state of the world to each continuation; taking the implicit state changes of an imperative language and making them explicit.
The real reason for using monads is that the scheme I just described is inhumanly complicated. Monads are a much more structured way of doing the same thing. Instead of writing these state passing CPS functions, you write functions that build them for you. A consequence of this is that monads perform much the same function as macros in Lisp; they are programs that build programs.