I was also overwhelmed by how convoluted the language seemed but eventually used it for a project, and my opinion completely changed. Haskell is a simple, beautiful language that enjoys great tooling.
Start out by learning just enough IO and monad stuff so that you can read input and pass it to your functions. This will not take long. Then you can gradually build up your knowledge of the language by creating modules that will become more and more idiomatic with time. You will discover parametrized types, laziness, and user-defined operators. At times you will struggle with how to use the type system to achieve your goal, but through practice, you will learn how it limits you, so you will know what approach to take.
Eventually you might notice that your code could be easier to read and write, and that’s where monads come in.
Somebody in this thread also recommended Clojure, which is a fine language that I would have also recommended a few months ago—it was my go-to language for spinning up servers or doing some computation. Now that I have tried Haskell though, I feel like I might not need to use Clojure again because Haskell is much more fun. So I’d hate for someone else to miss out on the fun like I did for years because they think they have to read a 600-page treatise just to get started! It’s very far from the truth.
That being said, all the choices you list (Elm, Haskell, F#, OCaml, PureScript) are solid languages with good communities. The core languages are similar enough that if you start learning one, the things you learn will transfer decently enough to all the others.
[1]: Haskell Programming from First Principles (http://haskellbook.com/)
In a sense, it feels like the textbook for a course combined with transcripts of the lectures... although it flows better than that, of course.
It's a mature functional language with interesting properties, it's practical, data oriented. Libraries quality are top notch, you'll find no big framework but libraries working together to achieve what you want.
Some ClojureScript libraries are awesome, for example if you're on React you have Reagent or Rum that are fantastic libraries to work with React.
OP post could be written like this in Clojure (if you want to be explicit with all the screens):
(defn needs-cancel-button [screen]
(case screen
:screens/loading true
:screens/code-entry true
:screens/success false))
You'll notice that this is not typed but you can use Clojure spec to have some validation (this way being less explicit just returning false for the Success Screen, and true otherwise): (def screens #{:screens/loading :screens/code-entry :screens/success})
(defn needs-cancel-button
[screen]
{:pre [(s/valid? screens screen)]}
(case screen
:screens/success false
true))
Union types can be mimicked using spec, you'll find how here: https://lambdaisland.com/blog/25-09-2016-union-typesOCaml is also great, IMO you won't lose your time by learning these languages, you'll find some way to improve your current code
Whether you learn Clojure, OCaml, F#, Haskell, Elm or Haskell, you'll end up being a better developer.
(If it helps, I'm primarily a python/js developer before picking Clojure).
Clojure's data checking and testing stories are good too, with spec and the various test libs - including generative tests from specs. And of course you can share the same specs on front and back end, demonstrating a payoff of the front/back code sharing.
PureScript is pretty much haskell, it simply compiles to javascript -- wouldn't say there is much skill transferability in terms of language when coming from js, but it might make sense if you develop front-end.
Don't know about the other languages.
I did manage to bundle a ~32mb hello world with dependencies/runtime (with cross-compilation, yay!) - but I couldn't get giraffe or any other server (framework) running in a reasonable amount of time. (Side-note, I'd appreciate a pointer to a f# Web server stack that works in the above scenario - something light that's appropriate to build a json-api server in).
Many tutorials appeared to be a year out of date, with wrong details - leading to code snippets not working, things not building, dependencies not installing.
Since I know ocaml is solid, I now am a strong believer in reasonml (which fixes some of the oddities with ocaml, making it more pleasant - in a way a little more like standard ml).
Reasonml has a strong Web app side, and compiles to sane js.
The other great option is clojure/clojure script. It's been dogged a bit by jvm (startup) overhead - not sure how/if graal/truffle AOT compilation will improve that.
For immediate productivity, I would recommend Scala - it's run on the JVM, and lets you fall back to a fairly Java-like subset. It's ugly in some ways, but has a more mature web programming ecosystem than a lot of other functional programming languages - a decent backend framework in Play and Scala.js for maybe writing a few critical browser-side libraries - and has decent and growing adoption.
If you're not looking for quick productivity in web development, and don't care all that much about learning a language that's immediately applicable to existing job opportunities, I'd probably recommend the more "pure" modern languages like Haskell or OCaml; they're niche, but it's a stable niche, especially in more academic circles, and will give you a cleaner mental model of all the features that are hackily being tacked on in JS and Scala.
I've heard good things about Clojure (think LISP on the JVM), but haven't personally tried it and don't know how vibrant its community is. Having access to JVM libraries, as with Scala, is a great plus for immediate productivity.
The series of if checks (O(n)) it generates as opposed to a switch statement can really add up in loops with bigger enums.
Of the langs listed, ReasonML/OCaml have the best codegen/ffi story, it’s relatively easy to drop them into existing JS projects.
Longerm, in my views, means being able to write software for web, desktop, multiple smart-phone/table platforms, with a backend in, ideally, the same language/tooling as front end.
It seems like ReasonML is the only one that is targeting the above [1] (but I could be wrong). And that's because of its integration/support of ReactNative.
[1] https://medium.com/@peterpme/your-first-reasonml-pr-into-an-...
Elm, Purescript and ReasonML feel like much smaller communities that I wouldn't trust to necessarily make for a good long-term investment; Haskell is a bit too much of a jump to get productive in immediately. If you learn like I do - incrementally - then you want a strictly-evaluated, mainstream-ey language that allows you to write side effects without tracking them, just to start with.
Elm is too limited, Haskell seems too convoluted, unsure about F# and OCaml, don't know about good alternatives.
I've been considering PureScript because it seems to strike a balance between features, JS interoperability and skill transferability, but I'm still a little afraid of it being unnecessarily complex for my next short-term projects.
I've only now started considering ReasonML, but am I wrong to think it's much closer to the "get productive fast" side than the "long-term investment" one? Not to mention its JS-like syntax, which I admit I have a distaste for.