The learning curve is one thing; dealing with purity and immutability is another. But the real stumbling block (besides the tooling issues) is the effect of lazy evaluation.
Lazy evaluation can make it quite difficult to reason about the time and memory resource requirements of Haskell programs, and debugging those isn't a whole lot of fun.
It is do-able, and like anything, gets better with experience, but it's hard to push things to production when you aren't sure they won't OOM or capriciously start doing some long thunk chain evaluation.
There is unsafePerformIO, but it's generally considered a really bad idea unless you really know what you are doing, and even then it is probably a bad idea. It is useful for debugging though and putting trace statements in.
Lazy evaluation can make it quite difficult to reason about the time and memory resource requirements of Haskell programs, and debugging those isn't a whole lot of fun.
It is do-able, and like anything, gets better with experience, but it's hard to push things to production when you aren't sure they won't OOM or capriciously start doing some long thunk chain evaluation.