📹 Hate reading articles? Check out the complementary video, which covers the same content.
If you have ever wondered which functional programming language is better than others, which one to pick, or which to learn — here is my subjective tier list.
⚠️ Note that I’m a bit biased towards statically typed languages.
💡 If you haven’t seen one of these, we go from D (bad/terrible) to S (the best/excellent).
Haskell
Let’s start with Haskell. If you can only take one functional language to the desert island, you should take Haskell because it offers so much. Sure, it’s not for everyone — it has a steep learning curve and can feel like throwing someone into the water to teach them how to swim — but it can be well worth it.
Laziness — a major reason to use Haskell, also a major source of frustration. Also, Haskell provides great concurrency mechanisms and powerful type-level machinery with great type inference. All of this has been there and stable for more than 20 years. Nevertheless, Haskell keeps growing — there is always more stuff to learn and experiment with.
Seems fair that Haskell is an S-tier fp language.
Scala
Scala, on the other hand, offers a gentler learning curve and you can dial up the functional programming at your own pace. You can’t go as “far” as Haskell, but you can go pretty far.
I have a special place for Scala in my heart.
I think Scala is an ideal fp language for Java developers and has an excellent free course for functional programming beginners.
Without doing any research, I’m pretty sure Scala is the most used fp language in production.
Scala also deserves an S-tier.
OCaml
OCaml is another language that offers OOP/FP flexibility. OCaml 5 was a strong release, which not only brought multicore but also a lot of attention to the language.
When people talk about OCaml, they often talk about a powerful module system, performance, and strong developer productivity (e.g., reversible debugger) — but I can’t speak on that because I haven’t used it in proper projects. I can talk about my favorite features: polymorphic variants and effect handlers. Polymorphic variants is my current preferred way of dealing with errors, and Effect handlers seem to me like a future of the control flow. Two features I wish every language had (or will have).
Overall, I don’t have much experience with OCaml, but S-tier
feels fair.
PureScript
Going back to a language I used: PureScript. I think it’s highly underrated.
How do I put it? It’s like a tidier version of Haskell — in my opinion, it’s easier to learn and get into.
It has a solid interop with the JavaScript world — so, you can slowly introduce it to your project and at the same time have access to the sea of js libraries.
On top of that, PureScript offers great records and row polymorphism. I know I keep bringing this up every time, but any time I have to manipulate some data, especially json, I miss not using PureScript.
Unquestionably S-tier.
Elm
Elm is a sibling of PureScript, and it’s even more focused. It’s both focused in the “features” it provides and focused on beginner friendliness. I bring this up in my video on values: it’s not for everyone but has a solid niche.
Elm is another great way to tap into fp from the frontend direction.
Because it has clear values and focus, it’s a solid S-tier.
Roc
If I understand it correctly, Roc is bringing Elm’s values and mindset to the backend. Or at least extending on those.
It has an attractive approach to balancing (or navigating) between prototyping and reliability — they promise a nice flexibility of dynamically-typed languages with a seamless switch to the other mode, where you actually handle both happy and error paths.
💡 I don’t have time to get into this, but if this sounds vague but exciting, I’d recommend looking into it (either watch a full talk on this or actually try it yourself)
On top of that, I think their anonymous sum types look fun (together with all the open and closed records and unions). And I’m also curious where their ideas around different platforms are going to lead.
Roc doesn’t have a “stable” release yet, but I say it’s an upcoming S-tier.
Unison
Unison is another new kid in town. And I think Unison can compete with Haskell on an amount of mind-breaking concepts. I don’t even know where to begin. Two of my favorite things:
1) Everything is a function: deployment is done with a function call, calling another service is a function call, and accessing storage is a function call.
2) Abilities — Unison’s implementation of direct-style algebraic effects, similar to OCaml’s effect handlers.
safeDiv3 : '{IO, Exception, Store Text} Nat
safeDiv3 =
do
use Nat / == toText
use Text ++
a = !randomNat
b = !randomNat
Store.put (toText a ++ "/" ++ toText b)
if b == 0 then Exception.raise (Generic.failure "Oops. Zero" b)
else a / b
Did I mention that they promise to eliminate yaml? S-tier.
Gleam
Gleam had a v1 release a couple of months ago. It’s a friendly language on top of Erlang runtime. It’s a simple selling pitch, but quite a strong one.
And they have the sweetest mascot. What other reasons do you need? S-tier.
F-sharp
Once again speaking of interop, F# might be an obvious fp choice for those on the .NET: either you’re using C# already or want to make games using popular engines.
And I keep seeing people bringing up F# for Fun and Profit — it looks really fun.
I haven’t touched F# — I’m a bit biased. So, S-tier.
Takeaway
As you might have guessed I’m pretty excited about functional programming. There are a lot of options, targeting different platforms, audiences, and values. Just pick your poison.