> Haskell is a good example of how you can overdo it, with the best intentions: concepts that are beautiful and frictionless in pure math become a cumbersome burden and an impractical cognitive load when translated too directly into a PL.
Why do you say this?
Sure, Haskell is radically different from most programming languages out there, even ones that claim to be 'functional'. But that does not mean it is 'overdone'.
With traditional imperative languages, you have years of experience behind you. Anytime you see a problem, you have those years of experience to guide you in choosing an appropriate way of solving it. All those idioms that you learn over decades of programming add up.
The problem with Haskell is that because it is so radically different, all that experience is largely useless. You start again from scratch. Remember the first time you learnt how to drive. It was confusing and you paid a lot of attention on every action and every turn. Eventually, with experience, it becomes instinctive and you don't even think about it under normal circumstances. Now, imagine that you wake up tomorrow, with all of that instinct gone. It would be utterly disorienting and scary.
Now, time for an anecdote: I've spent the bulk of the past one and a half years learning Haskell, with a couple of years of experience with other, partly 'functional' languages like Scheme and Python. In the beginning, I was extremely confused, and whenever I came across a problem, I had no idea of how to express myself in Haskell. This was completely alien to me. No other language I had come across had left me so lost.
However, in a few months, I came to learn functional idioms and began to grasp the language. What really appealed to me was how expressive the language was once you knew how to "speak" it. If you have to become 'fluent' in anything, you have use and think in it repeatedly. Eventually, it becomes second nature.
Because of how so many things in Haskell are based on solid mathematical foundations, it is extremely easy to generalize and most importantly, compose. Haskellers tend to draw a lot of inspiration from category theory(which I've also taken a liking too). The essence of the concept of "composition" is a category. It often astounds me how simple, generic functions and combinators can be strung together to form complex programs. I haven't come across this level of generality and composability in any other programming language.
Programming in Haskell, once you learn to "speak" it, reduces cognitive burden by a huge margin. Often, you deal with concepts so general there is only one way to implement them. You don't have to care about details of the underlying representation, because the number of representations is extremely vast. This is initially extremely disconcerting, and is probably the reason why people face so many problems with monads. The concept is so general, and has no single "concrete representation" that would make you grok it. When you ask "what is a monad?", people answer in a vast variety of ways. In truth, the only correct way to describe a monad is the monad laws. Anything that follows the monad laws is a monad. Those three laws are it. Newcomers are often astounded by that. How can that be it? The laws don't really say anything! They can't say much because they can be used to describe a vast number of things, from IO to exception handling to parallelism to non determinism. When you write code for a generic monad, you don't care about any of those detail, and what the monad you are dealing with actually is. All that cognitive burden is thrown away. In the beginning, it seems scary, but after a while I realised how liberating it actually was.