> You don't really need monads to perform io or specify sequencing in Haskell.

By implying certain logic dependence? It would be rather un-natural, which I assume is the reason for the invention of monad.

> Ultimately, if you want imperative style, you can just write imperative code that's well typed in Haskell.

It is not just a style. There are logic implications. In imperative programming, the states are always assumed. That is, the operations are assumed to have different effect switching orders. Note this is a much stricter assumption than the alternative that some/all operations are stateless. The benefit of such stricter confinement provides certain convenience. For example, because the order of instruction is meaningful and can convey ideas, contexts can take place, and local ideas can be focused (rather than carrying the whole states). In the real world (compared to the mathematical world), most action affects vast states that are impossible to quantify, and we (as an adaptive species) are well adapted to stateful imperative thinking. How do you perform rigorous logic thinking when the inputs (states) are never complete?

In computer programming, the states can always be fully described. However, if you always want to fully describe your states, you'll either restrict your functions and programs with limited states (input/output) or you will be constantly writing cumbersome functions/programs with a long description of all its states. The solution is to share and imply some of those states in the types, monad, for example. So yes, monad is not strictly a necessity but a convenience. Since Haskell never makes assumptions of hidden states, merely imitating an imperative style is still not imperative programming. Because the states are still not assumed, but rigorously specified and carried. So even with a seemingly similar code style, the cognitive process in Haskell and a conventional imperative language is very different.

Which is better? It depends. If you are holding the view that everything computer solves are mathematical problems, or when you are solving mathematical problems, certainly you would think only Haskell's approach makes sense. On the other hand, if you understand that computers are merely a tool for solving real-world problems, then you are often not looking for mathematically correct answers but practically good enough solutions. Practically good enough solutions allow room for shortcuts or undefined behaviors. Embracing these uncertainties (shock to mathematicians) allows for efficient means. Under the latter context, a pure mathematical restriction can be a burden rather than help. The latter approach, in fact, carries much more complexity. For example, calculating pi to one millionth digit. In functional approach, it is solving a mathematical problem and a correct answer is what you looking for. In imperative approach, memory cost, speed efficiency, various shortcuts are all part of the consideration and part of solution. It is not always just the answer matters, how you get the answer also matters. But do they really matter? It depends.

Real programming is often a mixture of both -- in C or in Haskell. C defaults to imperative style with explicit stateless when needed. Haskell defaults to stateless with explicit stateful when necessary. Trivial in one is difficult in the other.