A Rubyist learns Haskell, part 3
The end
October 23, 2024 · Felipe Vogel ·- Why did I want to learn functional programming, anyway?
- Y U NO HASKELL!?
- I discovered Roc
- … wait, but then why is that list archived?
- A sneak peek of what’s to come
I’m giving up on Haskell, and I’m 0% sad about it (OK, maybe 5% sad because of wounded pride) because I’ve found something a lot more to my liking: Roc.
… but don’t worry, you won’t be seeing a “Learning Roc” series anytime soon on this blog. I’m going to get back to writing about Ruby and web development, and put my explorations of functional programming on hold.
Why did I want to learn functional programming, anyway?
A couple years ago I posted half-baked thoughts on OOP vs. services for organizing business logic. The tl;dr is that I was intrigued about why so many Rails developers like service objects, and I wanted to understand them better despite my instinctive aversion to them.
As I wrote that post, I realized that some of the strongest proponents of service objects are also fans of functional programming. So at some later point I decided to go straight to the source and learn Haskell.
I’m glad I gave Haskell a try, but I’ve concluded that it’s not for me.
Y U NO HASKELL!?
Here’s how it went down.
I fought my way through Haskell MOOC up until Lecture 12, which is titled “fmap fmap fmap”… which somehow deflated my resolve to persevere through a few more lectures to the end of the course.
So I decided it was time to build a thing: a little CLI app that parses numbers in seven-segment display format, such as what you see on digital clocks. It’s a coding exercise that I’ve done before in Ruby, and now I wanted to try my hand at it in Haskell.
I did finish it, but my Haskell code is… a mixed bag. In the part where the app gets user input, my code looks horrendous. I’m a lot happier with the parts where I was able to write pure functions; here’s an example. (The commented section at the top is a doctest, which is what it sounds like: documentation that can also be run as an automated test. Doctest libraries exist in many languages, including Ruby!)
But in the end, the exercise didn’t revive my excitement to learn more Haskell. In fact, my list of things I don’t like about Haskell only grew longer:
- I find it hard to write readable Haskell code.
- It’s not easy to read other people’s Haskell code either.
- Writing Haskell gives me decision fatigue because it’s so flexible and you can write in so many different styles.
- Even more decision fatigue comes from how Haskell feels like a skeleton or “language toolkit”, rather than batteries-included. Maybe I’m spoiled by Ruby, but I didn’t like how often I had to hunt for packages and language extensions to get conveniences that I wish were built in to the language or standard library. For example, I had to use several language extensions to access record fields with dot syntax instead of globally-namespaced accessor functions, which seems like a pretty basic feature—and parts of that are still being ironed out.
- Writing high-performance Haskell is not easy, from what I gather, and involves arcane Haskell-specific knowledge. Not that I’m going to write a game engine in Haskell, but coming from a Ruby background, it would be nice to have a no-frills high-performance tool in my belt since Ruby is not that.
Even people who criticize Haskell say almost unanimously that learning it was a mind-expanding experience. But after months of (albeit slowly) learning Haskell, I didn’t have any grand insights. Maybe enlightenment was yet to come, but I was less and less excited about the grind in between.
So my Haskell learning slowed to a stop, and I declared it officially over when…
I discovered Roc
… so was my discovery of the Roc language.
Roc’s philosophy immediately clicked with me. At its core is a simplicity that I found lacking in Haskell, which gives it several advantages:
- It’s easier to learn.
- It’s easier to read, at least to my eyes. Compared to Haskell, it more often prioritizes explicitness over terseness and abstraction. See for yourself: compare “simple” Haskell code to any of the official Roc examples.
- It’s performant, aiming to outperform the fastest mainstream garbage-collected languages (Java, Go, etc.).
- It’s low-ceremony, tapping in to some of the strengths of dynamic languages (see also the upcoming “purity inference”).
I like Roc so much that it has replaced Haskell and Elixir in my “Learn functional programming” list.
… wait, but then why is that list archived?
Astute readers may have noticed that the GitHub repo for the above “Learn functional programming” list is archived.
In the end, I decided that I need to refocus my learning efforts: I want to explore some other problems closer to my roots in web development. Now that I’ve discovered Roc, it’s a good time to pause my foray into functional programming. Since Roc is a very new language, its syntax is still in flux, and I run into compiler errors now and then. So it’ll be a nicer learning experience if I come back to it later.
But I don’t want to discourage you from looking into Roc. These days I’m being extra careful with my time commitments for family reasons (namely, a toddler and baby #2 on the way), but if you’re less inundated and you have any interest in functional programming, you should totally try out Roc. For Roc learning resources, check out my “Learn functional programming” list. The links there are still up to date, as of October 2023.
A sneak peek of what’s to come
Since my enthusiasm for Haskell has run out and half of this post wasn’t about Haskell anyway, I think it’s safe to say this series is over.
Here’s a peek into (probable) upcoming posts:
- Alpine.js compared to Stimulus
- A CLI tool for doing Advent of Code puzzles in Ruby
- Another rewrite of my little app Wiki Stumble, this time in… JavaScript 😱