I have to disagree with the thesis here in its entirety. ADTs and pattern matching are not what makes Haskell good. Every article like this one just serves to show people the non-compelling bits of Haskell. The parts you can use in every other language, if you want to.
The parts of Haskell that make it a good language aren't the things that you can just write a tutorial for. They're about software engineering, not code snippets.
Purity and immutability remove entire classes of bugs caused by spooky action at a distance. When you assert this, people claim "I don't have those bugs", forgetting about the time someone else changed a function they wrote to mutate one of its arguments, breaking code three steps up the call chain.
Parametric polymorphism documents what information a function cannot use within its definition. If you point this out, people ask what good that serves. There's no way to explain how much easier it is to get things done when you can write a function and know that no matter what values are passed in, there cannot be special cases that trip you up.
I see people try to explain why the `Maybe` type is better than null values, and have their explanations rejected with "You still have to check for it. All you're doing is changing the syntax of the check." I've seen variations on that theme in maybe 10 different HN threads over the last 6 years. When all you talk about is ADTs and pattern matching, why would anyone ever look at the bigger impact of the type system? The relevant detail here is that an `Integer` can never be null, not that you use `Maybe Integer` to talk about potentially missing values.
Further in that same direction, I see people say that the `IO` type just complicated things because your program has to do I/O anyway, so it always needs to be in `IO`. This is exactly the same as the `Maybe` problem, but that similarity is even further from being addressed by articles about pattern matching and ADTs. No, the similarity isn't "monads". Anyone who talks about them here has missed the point entirely. The point is that parametric polymorphism completely prevents distinguishing IO values from non-IO values, so code that's not written to work with IO values cannot do IO accidentally.
There are a lot more cases, especially when you get into more sophisticated things possible in the type system using ghc extensions like generalized algebraic data types or higher-rank types.
But all of the reasons you should be using Haskell in reality come down to practical large-scale software design concerns. The language lacks features that make several common classes of bugs possible. It makes several other common classes of bugs take a lot more work to implement than the non-buggy way to solve the same problem. These aren't things you can just write a short article about. They're things that require years of experience and introspection to see are even problems, and a willingness to accept that a lot of the problem is the ecosystem, not an individual failure to execute. None of that fits in an article.
I think articles about how great pattern matching and ADTs are make the language look worse, because anyone with some experience can say look at what's actually happening and say "I can do that in <other-language>, Haskell clearly doesn't have anything to offer." In other words - stop writing these articles. They drive people away from Haskell, not encourage them to look at the good parts.
Honestly, I think it's worth bragging about just how much code re-use and modularity one can get out of combining parametric polymorphism with ad-hoc polymorphism (type-classes).
I literally, just this morning, found myself writing some annoying repeated glue-code, and realized I could shorten it up where it mattered by taking the glue and turning it into a type-class.
IMHO, people brag about type-classes too much with respect to the particular type-classes that embody category-theoretic constructions, and not enough about their original application to ad-hoc polymorphic overloading. If I can think of a Task X which I have to do for a variety of somewhat different types in somewhat different ways, but which is used in a polymorphic way, then I can absolutely make a type-class out of that.
It's like how people think the big secret to object-oriented programming is inheritance, but actual OOP experts tell you to prefer interfaces (which are almost-but-not-quite just like type-classes!) and abstain from building large inheritance hierarchies.
The parts of Haskell that make it a good language aren't the things that you can just write a tutorial for. They're about software engineering, not code snippets.
Purity and immutability remove entire classes of bugs caused by spooky action at a distance. When you assert this, people claim "I don't have those bugs", forgetting about the time someone else changed a function they wrote to mutate one of its arguments, breaking code three steps up the call chain.
Parametric polymorphism documents what information a function cannot use within its definition. If you point this out, people ask what good that serves. There's no way to explain how much easier it is to get things done when you can write a function and know that no matter what values are passed in, there cannot be special cases that trip you up.
I see people try to explain why the `Maybe` type is better than null values, and have their explanations rejected with "You still have to check for it. All you're doing is changing the syntax of the check." I've seen variations on that theme in maybe 10 different HN threads over the last 6 years. When all you talk about is ADTs and pattern matching, why would anyone ever look at the bigger impact of the type system? The relevant detail here is that an `Integer` can never be null, not that you use `Maybe Integer` to talk about potentially missing values.
Further in that same direction, I see people say that the `IO` type just complicated things because your program has to do I/O anyway, so it always needs to be in `IO`. This is exactly the same as the `Maybe` problem, but that similarity is even further from being addressed by articles about pattern matching and ADTs. No, the similarity isn't "monads". Anyone who talks about them here has missed the point entirely. The point is that parametric polymorphism completely prevents distinguishing IO values from non-IO values, so code that's not written to work with IO values cannot do IO accidentally.
There are a lot more cases, especially when you get into more sophisticated things possible in the type system using ghc extensions like generalized algebraic data types or higher-rank types.
But all of the reasons you should be using Haskell in reality come down to practical large-scale software design concerns. The language lacks features that make several common classes of bugs possible. It makes several other common classes of bugs take a lot more work to implement than the non-buggy way to solve the same problem. These aren't things you can just write a short article about. They're things that require years of experience and introspection to see are even problems, and a willingness to accept that a lot of the problem is the ecosystem, not an individual failure to execute. None of that fits in an article.
I think articles about how great pattern matching and ADTs are make the language look worse, because anyone with some experience can say look at what's actually happening and say "I can do that in <other-language>, Haskell clearly doesn't have anything to offer." In other words - stop writing these articles. They drive people away from Haskell, not encourage them to look at the good parts.