Learning Haskell (and Elm in the process)

Introduction

Functional programming has always had a certain allure to me. You catch whiffs of it writing workhorse languages like Python, and there’s certainly something satisfying about writing a concise, functionally-styled block of code where your university lecturers might have suggested using a nested for/while loop. I’d never had a “purely functional” experience before though, and eventually I felt the need to satisfy my curiosity. What pushed me over the edge was reading about GHCJS, a Haskell to JavaScript compiler. I was excited to use a language that’s almost synonymous with FP for web development.

I gave myself 12 days (it was mid-week and I wanted to finish on a Sunday) to get stuck in. Having a deadline on a project helps me prioritise and gives me a good reason not to waste time on ideas that are tangential to my goal, even if they’re worth looking into later. I didn’t initially know what that goal was, besides “learn Haskell”, and I didn’t see a reason to narrow the scope of that until I understood the domain better. In the end I wound up with something tangible that’s embedded further down on this page!

Reading

Usually I’d jump straight into coding by hacking away on examples or following step-by-step tutorials. Since FP contrasts so starkly with the OO paradigm, I decided instead to read a textbook on it. I chose Learn You a Haskell for Great Good, and besides some borderline offensive attempts at humour I can highly recommend it! It does a superb job of introducing concepts in a very logical order. The author regularly gives concise reminders of previously discussed concepts which really helps you understand them. It doesn’t provide much in the way of exercises, but that’s fine by me. I found it much more helpful to inspect chunks of code more thoroughly in GHCI (Haskell’s REPL) if I felt the need to, and to leave writing code until I had a better understanding of the language as a whole.

Inspired by a diagram in the book, I decided that my goals would be:

Snake seemed like it would be represented easily in Haskell since manipulating lists is so common in the language. I named my clone “Adder” since Haskell seems more aligned with mathematics than other language I’ve used and I didn’t feel like spending time coming up with a less unimaginative name.

It wasn’t until the Thursday before my deadline that I finished reading the book. I could have finished earlier, but at that pace my retention of its contents was solid.

Coding

A screen shot showing use of applicative functors, currying, and pattern matching in the Adder source code

Writing Haskell is fantastic. The declarative style is so elegant that it almost feels like writing psuedo code, which made it surprising when I ran the program for the first time and saw it running exactly as described. Pattern matching makes the corresponding imperative code look clunky and awkward. Currying and function application give you the sense that you’re working with something very cohesive and not just an arbitrary set of rules.

A screen shot of Adder running in iTerm 2

Concurrency wasn’t discussed in Learn You a Haskell so it took a bit more fiddling with than the game logic did, but otherwise it all came naturally to me. It’s not worth saying much more than that after such a brief learning period. In programming circles there’s definitely a culture of jumping to conclusions about languages or frameworks or libraries based on weekend projects, or even less qualifying experiences, so I’ll just say that I enjoyed myself!

Porting

Setting up a working GHCJS dev environment wasn’t as simple as I had hoped. I didn’t have much luck getting it to work in Stack (virtualenv/bundler/etc for Haskell) so I tried Reflex, an FRP library with a set of tools that makes it simple to get a dev environment up and running. I got as far as displaying the game’s initial state on a web page, but Reflex is pretty green and the documentation is sparse.

With only a day remaining, I investigated the alternatives. I settled on Elm quickly because of its maturity and superb documentation. There’s plenty of write-ups around about the differences between Haskell and Elm too. I set up an Elm environment, installed the Vim plugin, dropped my Haskell code into a .elm file and hacked away at it until the compiler stopped complaining, and hey, it works!

(On a desktop computer, the game will appear here)

On the whole, writing Elm was as much fun as Haskell had been. I missed certain features of Haskell’s syntax - the pattern matching isn’t quite as elegant, and dealing with monads felt clumsy - but the tooling and documentation more than made up for it. I also appreciate that learning the syntax on an ad-hoc basis means that I probably wasn’t making full use of the features available in Elm.

I cheated a bit in the Elm version by doing random number generation with the Native module, which sidesteps functional purity by glueing a chunk of plain JavaScript into the code. It would be better to use The Elm Architecture’s commands, but I didn’t have time to restructure the game to make it play nice with TEA.

Next

I didn’t get as far as writing graphics for Adder, but I’m happy with my progress. The “read first, code later” approach worked very well for me and I will certainly use it again.

When I have the time, I’d like to continue my work here:

The Adder code as it is at the time of writing is tagged with v0.1 here.

Update 11/03/18: I’ve since updated Adder with WebGL graphics. You can play it here!

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora