Maybe, but IMO it's often that the abstractions used to build software suck at it. Consider for example UI programming, the UI thread and event loop are hacks done because of lack of tools, performance with the current ones, and legacy environment/design. There is no reason why every event cannot be executed parallel, manipulated as push collections and have event handlers that perform application state transitions as transactions.
>and being able to reason about necessary state is how you do anything useful
I agree, and two parts need to be stressed in this, being able to reason and necessary state. Immutability/values make reasoning part transparent and necessary state is isolated in separate abstractions that again simplify reasoning about them.
I don't know how this applies to Haskell, but from playing with Clojure I can definitely see the advantages of working with values, even with single threaded programming reasoning is much simpler, and state is isolated in to Var/Ref/Atom/Agent primitives that have clear usage patterns and clean semantics (no gotchas with compiler reordering some instruction for lockless programming, no worry about lock acquisition order, etc.)