If you're interested in static functional programming, learn Elm and then F#/OCaml.
If you're interested in dynamically typed then learn Clojure or possibly Racket.
That's it. Spending time learning Haskell as your first (or even second) fp language is a terrible idea and has done more to slow FP adoption than anything.
You can learn Elm literally in a weekend it's so small and well organized (go to their site and follow the tutorial). The concepts you pick up will double the speed you learn any other static FP.
F# on .net core is cross platform and can run via a vs code plugin. Plus you have a batteries included full class library of practical needs via dot net.
Clojure is very productive, great concepts as well. A bit worse tooling / debuggingqgen you have to drop down to deal with java, but also had batteries included java libs.
Racket is probably the most isolated of the above. A scheme dialect and a bit closer to historical scheme and Lisp.
Don't learn Haskell it's a horrible use of time as a first language. You get 80% of the value in the above languages in somewhere between 1/10 to 1/4th the effort (depending on which lang you choose), and have learned a more practical language, and will actually learn that lang plus Haskell faster than if you had started in Haskell.
There is plenty of real-world Haskell code in production systems by industrial users.
The research is on practical applications.
The language I recommend as a first step to most people is Elixir (or Erlang). It's fairly pure, data is immutable, relies on recursion at the lowest level etc. Good code in Elixir is structure in a similar to good code in a lot of other functional languages (and so teaches good habits), but being dynamically typed is avoids that immediate pain of learning about how to keep the compiler happy.
I read a lot of code and didn’t get bogged down reading explanations of what a monad is. I also avoided trying to understand too well what the evaluation semantics of the language were.
When I read code, I focused on looking at the type signatures and understanding what they meant, then I would stare at the code and try to work out in my head why those definitions would get those types.
I did this at a time when there were lots of “I wrote a program in Haskell. Let me explain how it works” blog posts on this site.
I defined some data structures and solved a bunch of project euler problems as practice
My experience is that people get scarred of so much new terms which get introduced in Haskell and that could feel overwhelming.
When beginning with Haskell, I would advice to just write code and try to intuitively understand bits, but not get down into unwrapping things or theory much. Stay high level and figure out how things interact as you would do in black box model. Don't open the box, but poke it and see what result you will get (in other words; just write code and do trial and error).
When you get comfortable with black-box learning then open the box and look for the details.
I'm 6 chapters into Haskell Programming from First Principles [0], and I highly recommend it.
If you need to temporarily bypass purity there's unsafePerformIO and friends (or they can occasionally be used permanently if you do a lot of analysis I believe).
It's a pretty practical language compared to its reputation.
They are lamenting that implementing a trivial sorting function in Haskell is difficult.
quicksort [] = []
quicksort (x:xs) =
let smallerSorted = quicksort [a | a <- xs, a <= x]
biggerSorted = quicksort [a | a <- xs, a > x]
in smallerSorted ++ [x] ++ biggerSortededit: also, how is the pivot element selected there?
Obviously picking first element as pivot makes for a very poor Quicksort. Though I presume a better approach, say median of first, mid and last elements, would add but an extra line?
It is only linear when you force it to evaluate, which ideally happens only once (amortized) in your program when the result is consumed. As long as you are careful, you don't get the bad quadratic performance that you'd get from something like eagerly appending a character to a string in a loop in Java. There are either gotchas, though, including relying on the compiler to do things in constant space that naively look linear, and also knowing when the compiler won't help you and you have to structure your computation manually.
My biggest problem with Haskell is how GC and lazy-evaluation makes it very difficult to reason about what the hardware is actually doing at a given point. I know there ways to inspect and control it, but I've found myself preferring languages that have simpler mental models.
Quicksort isn't really hard, you just do it in IO and it looks about like what you'd see in any imperative language. (or you can use ST, but then you have to know about ST).
For non-debug, you may be overestimating how useful it is to output from pure functions in production.
In general when you are in a situation where you need to change the Monad you're under, there's techniques and libraries for that (one way you define it once, give it a name, etc.).
The biggest pain tends to be going from pure to monadic in the first place, which last I used Haskell there wasn't much for but to just do it. There may be more tooling now, haven't seen.
As soon as you need to control the order of execution, memory usage, IO, or any combination of those, you are fighting the language and into territory of things you can technically do and out of the realm of things the language makes easy.
I'd say that it's one take on that paradigm, the Way of Monads is not the only way to do purely functional, Clean uses uniqueness typing instead. Though it otherwise has rather similar properties to Haskell.
Monad itself is never a silver bullet. Type systems and Composability are the true power of FP IMO.
This is no reason to avoid arguably the most popular (and state-of-the-art) function language and implementation out there.
Space leaks I'd like to read more about but writings about them are a bit hard to come by. Recommendations?
SML by Dan Grossman is a great resource because it explains the concepts very well. Anything that you learn after will be easier, does not matter if you go for Haskell or F# later.
https://www.youtube.com/watch?v=a1fkhDjCHB8&list=PL-eVNDa9MN...