cvlad

My Haskell Journey

Introduction

It’s been a while since my previous post, but it’s been a crazy few months. I’m happy to be able to write again, and I’ll try to do it more regularly. This post will be a bit different; it will be a personal and entirely subjective description of my journey so far in functional programming. The reason I’m writing this now is because I will soon start working at Runtime Verification, my first FP job.

Background

I’ve been doing C# web development for about 15 years. Although I did not really understand much of FP, I was an eager early adopter of all functional-style features C# added over the years (LINQ, anonymous functions/lambdas, etc). Every other year, I’d look up the latest Haskell books or tutorials and give it a go, but it never really worked out for me due to various reasons (no real purpose, no sense of achieving anything, not understanding the benefits of what I’m learning, etc). Ultimately, I was never able to get past toy functions in the interpreter. But I was very intrigued by Haskell’s elegance.

The FP Slack Community

One of the best decisions I made was to look up FP-related communities. I stumbled upon the awesome FP Slack community. That’s where I found a bunch of passionate, helpful and very knowledgeable people. They pointed me into the correct direction countless times and helped me dodge frustrating experiences. Following is a list of the pitfalls I ran into while learning Haskell, along with what I wish I knew at the time.

Installing Haskell

In my experience, the best way to install Haskell is using stack. It’s a cross-platform tool for developing Haskell projects, and it helps with managing dependencies as well as GHC (the Glasgow Haskell Compiler) versions for each of your projects. Please check their documentation page on how to install. If you already have it, make sure you upgrade it via stack upgrade.

In order to start a new project, you can run:

vlad@rhaaw:~/code$ stack new project
vlad@rhaaw:~/code$ cd project
vlad@rhaaw:~/code/project$ stack build
vlad@rhaaw:~/code/project$ stack exec -- project-exe

You should now be able to edit either app/Main.hs or src/Lib.hs to change your program.

Writing Haskell Programs

I regret not listening to people’s advice about this sooner and spending a lot of time looking for the best Haskell IDE / development tools. In the end, everybody else was right and unfortunately, the current state of the available tools is not good enough. The process that most people seem to use, and the one I also adopted is using my favorite text editor with syntax highlighting. I have a few separate console windows that run ghcid and ghci.

ghcid is a lightning fast way to get feedback about your code as you work on it. Once you are in your project’s root, you can run stack build ghcid in order to build the appropriate ghcid version for the current project’s GHC. Once you do that, you can run ghcid using stack exec -- ghcid -c "stack ghci project". As soon as you edit (and save) any of the Haskell files in the project, it will recompile and let you know if anything is wrong.

There are a few interesting tricks you can do with ghcid, out of which I’d like to point out two that I find most useful. The first is really a GHC feature, which really shines when used with ghcid. Whenever you’re not sure what to do in a function, you can throw in an underscore and save the file. The compiler will figure out the type of what the underscore needs to be replaced with, and will suggest functions in scope that match that pattern. This feature is called typed holes, and if you want to read more about how it works, I suggest you read Christoph Hegemann’s excellent thesis, Implementing type directed search for PureScript.

The other trick with ghcid is, whenever you wish you had hover-to-see-type, you can add parenthesis around that expression and add a type annotation, e.g. (whatTypeIsThis :: ()). This basically asserts whatTypeIsThis has type (), or Unit. When you save, you will get an error saying that () cannot be unified with actual type of the expression (of course, unless the type actually is ()).

The interactive Haskell shell is great when you want to try things out, or do a quick test for a function you wrote. In order to launch it, you need to run stack ghci project. You can then type :l Lib to load the Lib module. Once you do that, you can execute any function defined in Lib. If you change the code in your source files, you’ll have to reload using :r.

Looking up stuff

Whenever I need to look something up, my go-to place is hoogle. You can search for functions or types by name and by signature. This feature was very useful for me as a beginner, since once you get a hang of types, you’ll sort of know what signature of a function you need but not know its name. As you look stuff up, I encourage you to look at the source code of the functions you look up.

When looking for packages, start with stackage, mostly because it will only show packages that are compatible with a certain GHC version and among themselves. If you try to mix and match by yourself through hackage, you might end up with frustrating problems.

Once you find a package you’d like to add, you can edit the package.yaml file under dependencies and just add the package you want by name. You’ll need to rebuild the project via stack build.

The Haskell Book

The most recommended book on the FP slack is Haskell Programming from first principles, and for good reason - it was absolutely key in my learning process. It’s filled with exercises guiding you through the Haskell language, as well as excellent explanations and tips. There isn’t much more I can say other than, if you want to learn Haskell, this is where you should start, and if you do, please work through the exercises.

Blogs and other resources

There are a lot of awesome blogs and resources for Haskell out there, and I want to mention particularly Matt Parson’s blog and Stephen Diehl’s What I wish I knew when learning Haskell as being excellent resources.

My personal interest in CS led me to reading several books on topics such as Type Theory or Category Theory. They are in no way required or necessary in order to learn Haskell, but they helped me and I think they are interesting:

Show and tell

Soon after I started reading the Haskell Book, I started understanding the benefits of FP. During this time, we were having some issues at work with the quality of our TypeScript code base. The code was brittle and we were often afraid to change it. I proposed we spent some time learning FP and try out PureScript (which is very similar to Haskell, but generates JavaScript).

For the next few months, I went through the Haskell Book and presented it bit by bit to my colleagues and did exercises together. This helped me immensely. Just preparing the chapters in order to present them to other people does wonders on your understanding; and actually presenting and trying to figure out answers to their questions was important for me.

Once we went through most of the book, we turned to PureScript. This has proven to be a very good choice for me, since PureScript is a slightly more modern language, and being already comfortable with JavaScript helped a lot. I was able to build useful software, while building apps that were familiar, in an unfamiliar way.

Writing apps

Shortly after, we started prototyping applications in PureScript and integrating them with our codebase. We were comfortable enough with the language to convince our management and product owners to let us create a PoC using PureScript, and they agreed. The results were impressive; we were able to develop the application about as fast as we would in TypeScript, with less bugs and back and forth with QA. The next app was even faster and the benefits more clear.

Applying for the job

I was not sure I was ready to switch to a full-time Haskell job when I found out about Runtime Verification and that they are hiring. In order to apply, I completed the K Challenge. This was ideal for me since I knew I could use as much time as I wanted for it. I ended up not needing too much time to get a decent implementation done, but the ease of mind that I could do it at my own pace mattered a lot for me.

Moreover, I was personally interested in Formal Verification, and the RV approach seems very appealing to me. I’m really happy to be able to be part of the team working on the Kore Language.

Closing thoughts

Because this is about Haskell, I’ve left out a lot of details about PureScript. I believe PureScript, as well as its incredibly friendly community, were very important in my journey. They helped me a lot and I’ll try my best to give back to this awesome community through code contributions and spreading the word.

I became a strong believer in FP, in strong typing, and in compilers guiding me through programming. I strongly believe that any programmer can benefit from learning Haskell. Even though I am still relatively new in this journey, I consider myself a better programmer than I was when I started this journey and I’m looking forward to learn more about Haskell, Type Theory, Category Theory, and Formal Verification.

Without trying to sound too stuck up in my newly discovered FP ivory tower, I’d like to point out that we, as programmers are extremely fortunate to get very good pay compared to the standard we are held against, most of the time. Chris Allen, one of the authors of the Haskell Book talks about this at LambdaConf, but my takeaway from it is, there’s no organization that takes away our programmer’s badge if we write terrible code or make bad decisions, or if we fail to stay in touch with technology or practices. But we definitely should, we should challenge ourselves to continuously learn, read other people’s code, contribute and, perhaps most importantly, work on projects outside of our comfort zone.