Oh, I think that nearly all of the problems with Haskell could be fixed up if it had the resources of C++ or Java. The problem is that in getting those resources, it would create new problems that would end up looking a lot like the whining about C++ or Java.

Java, as a language and a platform, is not fundamentally that bad. It was certainly done by very smart people with lots of experience.

It sucks because it has several design decisions embedded into it that were necessary for it to gain broad adoption and yet ultimately pretty annoying in the long run. Take closures, for example. The reason Java doesn't have closures is because it had a design constraint that all heap allocation must be indicated by the "new" keyword (same reason it didn't have autoboxing until Java5, and why classes aren't factory functions they way they are in Python). The reason for that was that at the time, the majority of programmers believed that heap allocation was slow and unpredictable, and in order for a new language to gain adoption, programmers needed to be able to control heap allocation and ensure it was used predictably.

This is actually still true - in domains like avionics and other "hard real time" areas, heap allocation is generally banned because it introduces nondeterminism into a program's run-time characteristics, and even with tuned incremental GCs, Java programs still spend a non-trivial amount of time in the GC. It just doesn't matter all that much, because Java started being used for applications where a few hundred millisecond pause for GC just gets lost in network latency.

Haskell faces a similar uphill battle. In order to get the critical mass of people needed to build out the ecosystem that C++ or Java has, it needs to be useful for the programs that people write today. But in order to do that, it needs to accommodate all these wonky developers with their weird ideas of what's necessary and what's not. Chances are, if it did that, there would be some design choices made that make Haskell nearly as lame as Java. And even if there aren't, and Haskell remains exactly the same as it is today, it'd soon be pushed into domains it wasn't appropriate for, just like Java, and people would be cursing it out for its flaws.

As Simon Peyton Jones says, "Avoid success at all costs."

There's a two-edged sword to every design decision that you make. Yes, Haskell gives you a lot of composability through lazyness, type inference, and nearly everything being first-class. Lazyness grants this through "pay for only what you use" - if a caller never uses the result of a library, the parts of the library's code that generate that result will never be invoked. The flip side of this is that if you suddenly use one more field in a tuple, way down the line in some unrelated portion of the code, you might trigger a very expensive computation. This is unacceptable in many large apps written by multiple people; you shouldn't have to worry that a tiny field reference can bloat the program's memory consumption by orders of magnitude.

(I have example trade-offs for type-inference and first-class everything, as well, but this post is already getting too long, and I wanna go do other things with my Saturday. ;-))