It's not that I don't think that programming in a functional style isn't a good idea , it's just that the discussions about functional programming and the languages people use to implement its style so often suggest: If you use language 'x', then using mutation is wrong. and recently, I've been thinking about the practically important but socially awkward question: What language is best for implementing mutable state…
Haskell has a nice approach to that problem. Data is immutable by default, but mutable primitives are available. The type system forces you to be explicit about when you're using mutability, so that mutable data can never accidentally creep into logic where you relied on immutability for correctness.
Broadly speaking, most mutable data types fall into two categories: Those that are some flavor of "IO," and those that are some flavor of "ST." In brief, the IO type is Haskell's way of dealing with operations that logically must be performed in the right order. (In-place operations require as much.) You can think of IO as one continuous chain of operations that begins and ends with the lifetime of the program. In other words, you can't just drop in and out of IO at will; the chain must be unbroken.
ST is an interesting variant on the same idea, except it does allow you to drop in and out at will. That is, I can enter ST at any point in my program, including the functionally pure parts. How is this possible? Because it imposes a restriction that's not present with IO: You must not touch the outside world from within ST. In any ST function, you get your own little mutable sandbox, but as with any pure function, you can only see that which is passed to you, and all you can do to the outside world is return a value. So you can, e.g., take an immutable list, create a copy that you sort in-place, then return the sorted list as an immutable value.
IO and ST are each flexible in their own ways. With IO, you can do almost anything, including mutating something that's passed in by reference. That can be important for some programs' performance. ST is flexible in a different way: You can sneak it into pure functions.