Studying Functional Programming in 2015: A retrospective
12 Jan 2016
In late 2014, I noticed a trend in the front end developer community: there was talk of this magic power called functional reactive programming. As it goes, I started sensing enough of a buzz that I became curious. One of the catalysts that really spiked my interest in the topic was this talk from Jafar Husain at Netflix. Functional and functional reactive programming sounded intriguing and they seemed to have really interesting applications for user interface design.
I was really looking to grow as a programmer so in early 2015 I decided to learn a new programming language. I wanted it to be a functional one and I settled on Elixir because it seemed to take a lot of inspiration from Ruby which I know and love. Elixir excels at building distributed, fault tolerant servers. This put me in a situation where I was tackling 3 big things: a new programming paradigm, a new language, and a new problem space. It went badly.
Elixir was a delight. I learned a lot going through some basics but my pace was at a crawl. I was trying to squeeze too much into too little time. In the summer of 2015 I decided to try a different approach so I switched to learning Elm. Elm excels at building user interfaces which is a problem space I am quite familiar with. This brought me down to 2 big things: a new programming paradigm, and a new language.
Elm has been a lot of fun but still a big challenge and a great opportunity for growth. I continue to learn it and am working productively towards building a non trivial thing with it. I plan to write some more focused blog posts about Elm soon.
For the rest of this article I will talk about what I believe functional programming is all about, some of the concepts covered in that course, and my next steps for learning functional programming.
What is Functional Programming?
So far, the best description I have found is in this blog post: What is Functional Progamming?. The blog post describes a functional programming language as “[a language] that supports and encourages programming without side effects”. The essence of programming in a functional style is learning to identify side effects and then using various tools or programming patterns to ruthlessly eliminate them. In cases where you need to have an effect (for example making an http request), you use the patterns to strictly corral those cases into a few well defined places in your program.
Side Effects and Pure Functions
A side effect is when a function affects the world outside of itself. A pure function is a function that always reacts the same way to the same inputs without causing side effects. A pure function will always return the same result for the same inputs in any context.
Pure functions also come along with some useful properties. If a function doesn’t fit any one of these properties it probably is not a pure a function. Pure functions are:
- Testable - They are easy to test without creating mocks or fixtures.
- Portable - They can be used in any context and still behave the way you expect them to.
- Memoizable - They can be memoized.
- Parallelizable - They can be run in parallel without causing mischief.
- Would need a fixture in order to test it.
- Can’t guarantee the same result if it was run in a different context.
Basically any DOM mutation is a side effect. This function is not pure.
This function is not parallelizable. If you ran it across multiple threads you would not be able to guarantee the sequence of the logs. Logging to the console here is a side effect. This function is not pure.
This function will always return the same result when given the same inputs. Note that if the dictionary had not been passed in we wouldn’t be able to guarantee that. Since we did pass in the dictionary this function is pure.
Avoiding Side Effects
An interesting pattern that emerges when programming in this style is that all of the effects you actually want to happen (i.e. user input, printing out messages, making HTTP requests) get pushed to a few controlled boundaries in your program while the bulk of your program remains completely pure.
Let’s take a look at some of the tools.
Currying is a tool that let’s you pass arguments to a function one at a time. The function returns a new function until it has been given all of it’s arguments at which point it returns a result. This is much easier to explain through examples.
Notice that when creating curried functions, you should always put the data to operate on as the last function parameter.
Function composition let’s you build up more elaborate functions from a collection of existing simple functions. The coolest part of this technique is that it let’s you create a sort of pipeline of operations that will act on your data. This pipeline is set up in a way that is incredibly easy to change.
In the examples,
compose is a function that creates the pipeline. The pipeline sends the data through the functions from the rightmost function to the left.
Notice how easy it was to add to the pipeline and create
shoutTwice? Reconfiguring the composed functions becomes trivial once you have your basic functions set up. Cool stuff!
Monads are yet another magical item used in the quest to eliminate side effects. Going through the details would make this already long article ridiculously long so I will just briefly mention them as one of the cornerstones of the functional programming style.
Monads are a construct that have to follow a bunch of rules but they are essentially containers around data. You access the data by mapping over the container, otherwise you work with the container when doing function composition and building up your program. There are a whole bunch of different Monads that give you various magical powers. I urge you to read Chapter 8 of the Mostly Adequate Guide if you want to learn more about them.
At this point I am just beginning to understand why this style of programming would be a benefit. With more practice, I hope to move towards a place where I really feel the advantages.
Although I don’t follow the functional style in my daily work, some of the ideas have started to stick and are influencing the way I write code. I am starting to really notice hidden inputs and side effects. Whenever possible I take steps to make them more explicit even if I can’t figure out how to eliminate them.
The goal all along has been to learn and practice a style of programming that would challenge my existing understanding and push me into new and exciting territory so that I will grow as a programmer. With that in mind, I would say that my exploration of functional programming has been a resounding success.
I want to give special thanks to Joe Nelson and Brian Lonsdorf who did an amazing job of unpacking these ideas in the Front End Masters course. Brian has also created an amazing online book called “Professor Frisby’s Mostly Adequate Guide to Functional Programming”. Check it out!
- What is Functional Progamming? by Kris Jenkins
- Make the Back-End Team Jealous: Elm in Production by Richard Feldman
- Learn you a Haskell for Great Good! by Miran Lipovaca
- Professor Frisby's Mostly Adequate Guide to Functional Programming by Brian Lonsdorf (dr boolean)
- Elixir Programming Language
- Elm Programming Language