Learning Functional Programming #1

Matthijs groenPosted by Matthijs Groen on 16-2-2021

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:

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!

Matthijs groen

Matthijs Groen

Full Stack Web Developer • Hobby Indie Game Developer Github: matthijsgroen • Twitter: @matthijsgroen

Bij Kabisa staat privacy hoog in het vaandel. Wij vinden het belangrijk dat er zorgvuldig wordt omgegaan met de data die onze bezoekers achterlaten. Zo zult u op onze website geen tracking-cookies vinden van third-parties zoals Facebook, Hotjar of Hubspot. Er worden alleen cookies geplaatst van Google en Vimeo. Deze worden gebruikt voor analyses, om zo de gebruikerservaring van onze websitebezoekers te kunnen verbeteren. Tevens zorgen deze cookies ervoor dat er relevante advertenties worden getoond. Lees meer over het gebruik van cookies in ons privacy statement.