
This post is part 1 of the series “Learning Functional Programming using JavaScript”. Already read part 1? Part 2 and part 3 of this Blog Post series are out now!
Functional Programming
Hi, I’m Matthijs Groen, a frontend developer at Kabisa and I would like to share my experiences with diving into the concepts of Functional Programming.
Before we dive into the Functional Programming (FP) goodness, I’d like to share where I was coming from and why I had so much trouble adjusting to the FP concepts.
I spent most of my developer life writing object-oriented code and some procedural code before that. In Object-Oriented programming (at least how I was taught) how you name objects, methods etc. matters.
I have worked with Ruby on Rails for years. Not only was everything an object in that language, Rails itself is a framework with “conventions”. These conventions make you productive in some cases, but also make you feel trapped in others.
1
2
3
3.times do
puts "This will be printed 3 times"
end
Yes, even a number is an object.
After working with Ruby (doing full-stack), my work changed to be more front-end only. We used Backbone.js for years. Backbone, just like Ruby on Rails is Object-Oriented, and follows the Model-View-Controller pattern.
A few years ago we changed the front-end stack from Backbone.js (in combination with CoffeeScript) to Preact, Redux and modern ECMAScript.
The thing I liked most when I just switched from Backbone.js to Preact was the way you could nest views. In Backbone this really was a pain. So you would end up with big templates. In Preact, you make a small reusable component for everything, and nesting views was actually the way to build up your UI.
It also changed for us where logic lived.
The location of logic was no longer decided by the framework. You could put it everywhere. This made the business logic totally separate and on its own. Easier to test, in loose small functions. No framework to have any opinion about it. Data in, data out. Just functions, and functions calling other functions.
No hidden dependencies, or object hierarchies.
It makes refactoring or moving code around a breeze. Now not only the views were composable, the whole software became composable.
1
2
3
4
<HeaderBar theme="blue">
<SiteMenu />
<UserProfile user={user} />
</HeaderBar>
Nesting views (Components) in Preact is as easy as nesting HTML self.
First steps…
I really started to like this approach. In the meantime, I got more colleagues on my team that really were into functional programming. Elixir, Haskell, Monoids, Functors, Category theory. I didn’t understand half of what they were saying. And when I asked to explain stuff to me, most of the time it only gave me headaches…
But I really started to like working with functions only approach. No
getName()
that could reply with a different value each time you called it. It
became more predictable. Also working with Redux brought new concepts to the
table such as immutability. Not changing data, but reconstructing new data based
on changes.
An example:
Before:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Person {
constructor(firstName, lastName, age) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
getName() {
return `${this.firstName} ${this.lastName}`;
}
getAge() {
return this.age;
}
increaseAge(amount) {
this.age += amount;
}
}
const me = new Person("Matthijs", "Groen", 37);
me.getAge(); // 37
me.increaseAge(1);
me.getAge(); // 38
me.getName(); // Matthijs Groen
After:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const me = {
firstName: "Matthijs",
lastName: "Groen",
age: 37,
};
const getName = (person) => `${person.firstName} ${person.lastName}`;
const getAge = (person) => person.age;
const increaseAge = (person, amount) => ({
...person,
age: person.age + amount,
});
getAge(me); // 37
const olderMe = increaseAge(me, 1);
getAge(me); // still 37!
getAge(olderMe); // 38!
getName(me); // Matthijs Groen
There are more benefits:
- Since a function only relies on its directly provided input and is not allowed to change that input, not handling the result would actually make the function call as if it never happened.
- When you are not allowed to change things, you know what data you are dealing with. It did not change by itself, unless you got new data after calling a function to change the data.
- Since this relation of input and output is so strict, you can cache processes better, skipping performance heavy steps.
- Reusability is very, very high. Functions have less responsibilities, are generalizing data patterns and allow for great composition into larger solutions.
So I wanted to learn more about these concepts, and practise them. I wanted to understand all “the fuss”.
But there is a big gap coming from an object oriented world, where language were designed to be easily readable and code was written as if they where stories, and going to a world where stuff is expressed as math and concepts with strange names are explained by even stranger names.
1
fmap :: (a -> b) -> f a -> f b
yep.
A colleague pointed me to “Functors, applicatives and monads in pictures”. By just reading the article it was hard to make something out of it. It started to make sense to me only after I opened the browser console and started typing JavaScript to try and follow along. Learning by doing works better than reading alone.
Opening the browser developer console for this series is also a great way to follow along what I am building 🙂
I could replicate the concepts, but I did not understand them, or how it would help me write better software.
I was intrigued by a video about Parser Combinators by Scott Wlaschin, because I work and create DSLs in various projects. It looked like fun to build something like that for myself.
So I decided to create a challenge for myself, to learn more about Functional Programming and playing around with the concept of Parser Combinators.
The Challenge
Since I’m more of a learning by doing kind of guy and work only in JavaScript
nowadays, I opened my editor and defined the following challenge in a
challenge.js
file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const data = `
{
"name": "Functional programming challenge",
"goal": [
"create a function that takes one argument that is a path into this JSON struct",
"get(data)(\\"using.disallowed.0\\") should result in \\"Dependencies\\"",
"get(data)(\\"points.full-json\\") should result in 1000",
"get(data)(\\"jsonTypes.2\\") should result in false"
],
"using": {
"allowed": [
"Only code in this file",
"Only functions that take one argument",
"Ternary operator true ? a : b"
],
"disallowed": [
"Dependencies",
"Recursion to own function",
"JSON.parse",
"Usage of 'if'",
"Usage of for/while loops",
"Usage of functions before they are defined",
"Host object functions (.split, .map, .reduce, etc)",
"Multiple statements in a lambda"
]
},
"hints": [
"Think about function composition and currying",
"Think about parser combinators",
"https://fsharpforfunandprofit.com/posts/understanding-parser-combinators/"
],
"points": {
"not-trying": 0,
"started": 5,
"full-json": 1e3,
"without-recursion": 1e4
},
"jsonTypes": [null, true, false, -0.12]
}
`;
/**
* So, not like this!
* no function usage of the host language, no dependencies
*
* import get from "lodash/get";
*
* const ast = JSON.parse(data);
* const get = ast => path => get(ast, path)
* console.log(get(ast)("using.disallowed.0"));
*
*/
Would I be able to create purely functional code to parse the defined JSON?
Yes, I even added a Recursion to own function
in there, after watching
“The next great functional programming language”
just to see if it would really be possible.
In this talk, John de Goes argues that a good programming language could do without:
Pattern matching, Records, Modules, Syntax, Type classes, Nominative typing, Data, Recursion
https://www.slideshare.net/jdegoes/the-next-great-functional-programming-language (see slide 11 for the list)
Having the blogpost of Parser Combinators ready at hand, it would be a simple exercise of following along and implementing it in JavaScript and trying to apply a few more rules along the way.
But I was wrong!
I never knew I would learn so much in a few days…
In the upcoming posts I would like to take you along the journey I made into Functional Programming. This post deliberately ends here, so if you would like to do the challenge yourself, you can do so without spoilers.
Note:
I originally did this challenge in the beginning of 2019. I revisited this challenge again in 2020, and did a typescript implementation. (to learn typescript as well 😄) It does not change the concepts used here, but the implementation will slightly differ. When it makes sense, typescript parts are included as well. (full typescript and javascript implementations will be shared at the end of the series).
My Journey in learning Functional Programming #2
Already read part 1? Part 2 and part 3 of this Blog Post series are out now!