So far, we haven't written anything interactive in Haskell. All of the interactivity has come from the environment, which reads some Haskell, runs it, and then finishes. To start with some interactivity, we'll look at the getChar function. This, like its C equivalent, reads one character from the keyboard:
Prelude> getChar '\n' Prelude> getChar x'x'
Obviously, this is not a pure function—it doesn't return the same thing across two calls. How does that work in Haskell? Let's look at its type:
Prelude> :type getChar getChar :: IO Char
The IO here is a monad. As I discussed in my last article, a monad is a sequential set of computational steps. You can think of it as a big lambda term at the front of your entire program, binding the program to the real world. I'm reliably informed that this is entirely the wrong way of thinking about monads, but it seems to work for me.
There's a lot of explanation about how to use the IO monad available, so I won't repeat them. It's worth remembering though that monads are for a lot more than IO. They are for any sequence of operations that need to be serialized.
My favorite example is the STM monad, which implements software transactional memory. Transactional memory is a blob of shared state in which a sequence of changes is either all made together or is not made at all. This means that you can implement complex read-modify-write (or read-copy-update) operations in Haskell using more or less the same syntax as you use for monads.
A full discussion of how to do this would be much longer than this article, but I'd thoroughly recommend that anyone interested read Simon Pyton Jones' paper Beautiful Concurrency which discuses it in some detail.
Don't Stop There
This article has hopefully given you some idea of why it's worth learning Haskell. Even if you never write any Haskell code, you'll find that a lot of the ideas are useful elsewhere. For example, most languages now include equivalents of the map function and other higher-order functions that are incredibly common in Haskell. I've recently started using a construct a lot like a Monad in a parser generator that I'm working on to allow the parser to backtrack without the user needing to be aware of the backtracking.