A more appropriate comparison would be with commonly used high level languages such as Java and Python. The comparison here is meaningful because you'd build similar software with them as you would with Haskell.
A more appropriate comparison would be with commonly used high level languages such as Java and Python. The comparison here is meaningful because you'd build similar software with them as you would with Haskell.
Well-written programs in C++ are very different from programs in good C. (Bad programs are all alike.) C++ programs may be easily as "high level" as Haskell ones, higher than is possible in Java. C++ is clearly the language to beat, as no mainstream production language rivals its performance or expressiveness.
I haven't been able to get exposure to a language that is comparable in abstraction power with Haskell, except for DSLs.
Algebraic data types and GADTs are clever ideas very far removed from most real problems faced by real programmers, who have problems no language helps much with, and where the best we, as language designers, can do is try to keep the hell out of the way.
C++ has lots of such stuff too, mostly in template land. They can be useful to maximize the generality of libraries -- sometimes enabling great libraries -- but for most programmers most of the time they are at best a distraction, and more typically generate mysteries that absorb unbounded time.
Mark Dominus has some of the most insightful writing on the experience of coding Haskell.
Everything else you've said has a case that can be made for it but algebraic data types being removed from real problems is utterly false. The contortions that Python programmers (myself being one of them) have to go through in the absence of ADTs are mind boggling. There's no language without sum types that wouldn't be significantly improved by their addition.
In Haskell as in C++, they serve as an escape valve where the formal type system is too constraining. In C++, we see std::optional, std::variant, and boost::result, and don't find we need many more.
Product types are ad-hoc structs, analogous to lambdas as ad-hoc functions. They are important to enable compounding of libraries from different sources, aside from their frequent convenience. Compounding libraries is still hard for other reasons, and so not useful as often as might be hoped.
In Python you have the opposite problem of C++ and Haskell: everything could be anything, and you would like them to be guaranteed to be only one or a few things.
As for ADTs and the like, these are very basic features used all over Haskell code, combined with pattern matching. There are much more advanced abstraction concepts that are used all over Haskell libraries.
I'm sure C++ has good facilities for abstraction. However, as it lacks many of the very advanced abstractions that Haskell has, I find it far fetched that C++ could be described as an equally high level language as the likes of Haskell. From what I understand, that's not even the intention of C++ to begin with.
Btw thanks for that reference to Mark Dominus, seems like interesting stuff!