If you need to temporarily bypass purity there's unsafePerformIO and friends (or they can occasionally be used permanently if you do a lot of analysis I believe).
It's a pretty practical language compared to its reputation.
For non-debug, you may be overestimating how useful it is to output from pure functions in production.
In general when you are in a situation where you need to change the Monad you're under, there's techniques and libraries for that (one way you define it once, give it a name, etc.).
The biggest pain tends to be going from pure to monadic in the first place, which last I used Haskell there wasn't much for but to just do it. There may be more tooling now, haven't seen.
They are lamenting that implementing a trivial sorting function in Haskell is difficult.
Quicksort isn't really hard, you just do it in IO and it looks about like what you'd see in any imperative language. (or you can use ST, but then you have to know about ST).
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSortedIt is only linear when you force it to evaluate, which ideally happens only once (amortized) in your program when the result is consumed. As long as you are careful, you don't get the bad quadratic performance that you'd get from something like eagerly appending a character to a string in a loop in Java. There are either gotchas, though, including relying on the compiler to do things in constant space that naively look linear, and also knowing when the compiler won't help you and you have to structure your computation manually.
My biggest problem with Haskell is how GC and lazy-evaluation makes it very difficult to reason about what the hardware is actually doing at a given point. I know there ways to inspect and control it, but I've found myself preferring languages that have simpler mental models.
edit: also, how is the pivot element selected there?
Obviously picking first element as pivot makes for a very poor Quicksort. Though I presume a better approach, say median of first, mid and last elements, would add but an extra line?
As soon as you need to control the order of execution, memory usage, IO, or any combination of those, you are fighting the language and into territory of things you can technically do and out of the realm of things the language makes easy.
I'd say that it's one take on that paradigm, the Way of Monads is not the only way to do purely functional, Clean uses uniqueness typing instead. Though it otherwise has rather similar properties to Haskell.
Monad itself is never a silver bullet. Type systems and Composability are the true power of FP IMO.
This is no reason to avoid arguably the most popular (and state-of-the-art) function language and implementation out there.
Space leaks I'd like to read more about but writings about them are a bit hard to come by. Recommendations?