From my (limited) experience with Haskell, my impression is that it's strongest in domains that map _very_ well to formal mathematical models. Mathematical computation is an obvious example, but things like programming language parsers are also really intuitive to build in Haskell.
My experience trying to use Haskell for other stuff — mainly, building web backends, my bread and butter back then — was painful. Simple CRUD against a database is actually pretty decent thanks to there being decent Postgres drivers and libraries, but the moment you need to handle arbitrarily-nested data structures (like a JSON request/response with a nontrivial schema), you run up against a lot of awkwardness, to the point that for the longest time this was known in Haskell as the "records problem."
Lenses and similar tools have tried to solve this problem over the years, and maybe they have, but I moved on from the language when I saw how deep that rabbit hole went.
None of this is to say Haskell isn't fun or rewarding, but it definitely has its strengths and weaknesses.
The records problem is basically a small syntactical quirk. Undesirable, yes, but not what will make or break production software development.
Lenses solve some of that and much more. Lenses strictly improve on fields/records/getters/setters/etc. in any other language you know. In other words, they accomplish what they do and then some.
If that was your only problem with Haskell, then it might be one of your favourite languages if you get to know it again.
I still think it's worth learning by anyone who's got the time for it.
While I totally sympathize with this, I'm not sure it's a very good vantage point from which to judge a language.
Where are the practical Haskell tutorials. No preaching, no "you're holding it wrong", ONLY this: "you need to handle arbitrarily nested JSON? here's how".
- Simple Haskell Handbook[1]
- Haskell (Almost) Standard Libraries[2]
- [0]: https://lhbg-book.link
Learning an entirely new language is hard and requires patience and perseverance!
Haskell was created by researches who wanted to study properties of lazy functional programming. I’ve never heard anyone say they did it because lazy evaluation was “good”, it was their area of research. The co-creator has even said that if he had to do it over again it might be better if it were strictly evaluated.
I worked in Haskell for a few years before switching over to a very closely related but strictly evaluated language, PureScript.
The pureness and laziness of Haskell forced the creators to work out monads for IO which I find extremely useful. Haskell-like monads certainly can (and have) been implemented in strictly evaluated languages.
I don’t miss implicit laziness very often, but I’ll say with partially applied functions, it’s nice to know that values will be calculated as needed and results shared across invocations once those functions are fully applied. That’s something I wish we had in PureScript. Note that in addition to laziness this also requires a compiler optimization that moves let bindings out of inner functions, aka let-floating.
Laziness is also nice as it allows you to be very declarative, defining what things are without ever worrying about the calculations running when you don’t need the result. In practice it’s easy enough to create thunks manually and evaluate them when needed. Doing this can get tedious and the resulting code is less succinct.
Articles of that form are usually BS though, for any language. These are general purpose programming languages. They all have different benefits and drawbacks, but you can usually use any of them to do anything you want.
And everywhere else, unfortunately.
Go is an overreaction in the opposite direction. In 2010 I can't agree that there is a good reason to make a language without generics and reasonable error handling from the very start.
Kind of getting sick of hearing these same complaints, over and over, to be honest.
(my background is mostly python, R, javascript, clojure)
I don't completely buy the argument that a Google backed Haskell would have been as popular as Go. Readability (which is subjective), familiarity (often C is the reference), and the ease of which the language can be learned are still major factors in widespread acceptance.
There isn't much that only one programming language can do, so it's not fair to ask for this. The benefits of using Haskell over other programming languages are that it's easier to reason about code in it, and you can have more assurance that code is correct.
“In other communities people mostly discuss regular production problems and data structures, while in a Haskell chat people discuss monads, applicative functors, crazy types and things like that.”
This is why use cases and how only Haskell enabled solving it are rare.
The inofficial motto of 'avoid "success at all costs"' is not a joke. It's easy-ish to achieve success if you allow yourself to pander to the masses who don't always understand what they are missing, and there's always been an element in the Haskell community that tries to do what's right, notwithstanding what the large masses think.
This desire is usually expressed with sentiments like "let's make this easier to learn" and "Let's fix this so it's not a footgun", and not "success at all cost".
How about: the least-valued of all goals?
The lesson I derive from Haskell is that "If it compiles, it will work"
1. is inflated nonsense
2. has a lot less to do with Haskell-the-language than with Haskell-the-type-system
I have observed a similar phenomenon with Rust. That statement is not perfect, it's hyperbole. If it compiles, it doesn't mean it will run (otherwise, why bother writing code? We just write function signatures and call it a day).
But Rust's type system is incredibly sophisticated, just like Haskell's.
And guess what... Rust supports mutability. It doesn't just support it, it encourages it. It tells you "Step over that fence, it's okay, I got your back".
It's so liberating.
The secret here is not functional programming. It's not immutability.
It's a sound and powerful type system.
The whole avoid success at all costs looks more like a meme to me than actual strategy. There are functional languages (Clojure(Script), Elm) which made pragmatic decisions about the feature sets and have found commercial success. But with Haskell, it seems a reverse process was followed. It starts with some (questionable?) assumptions like lazy evaluation is good and then builds on top of it. For commercially viable software, the process is generally reverse. You start with specific problems and build a feature set from it.
The best way to understand this academic Vs. pragmatic approach is to look at Golang's relative success vs Haskell. No matter how much PL researcher snobs complain about golang, its creators started from real problems and chose some constraints carefully. The result is its widespread adoption in its niche (networked infrastructure code that can tolerate GC). Such cases are not documented for Haskell or are rare to find.
It is perfectly alright and better to say, look this was a research language to find out how far we can go with certain choices and assumptions. But constant evangelism about how it is elegant etc does not help.