JS Monday 09 - Understanding Functors

When you’re digging deep into a language or a paradigm, you’ll inevitably find some concepts that are hard to understand.
Not every developer have an academic background so same concepts, terms or abstractions are hard to understand and adopt.

One concept that’s certainly hard to understand is: what is a Functor?
Well, I bet you’re already using functors every day without knowing it!

A Functor is a map between two categories.

Real world example? The awesome .map method from our first article, can be applied on arrays… which are functors!

As written in the Haskell Data.Functor specification, Functors uniforms action over a parameterized type, generalizing the map function on lists.

Let’s throw away all that abstract things and let’s see in practice how to adopt Functors!

Functors in practice

As you can see in the example above, an array is functor because we can map over it.
We can apply a function to each element and get back the same structure, respecting the Functor Laws:

  1. Functors must preserve identity morphisms
    When performing the mapping operation, if the values in the functor are mapped to themselves, the result will be an unmodified functor.
  2. Functors preserve composition of morphisms
    If two sequential mapping operations are performed one after the other using two functions, the result should be the same as a single mapping operation with one function that is equivalent to applying the first function to the result of the second.

So as you can see, we can applydouble and add5 functions to our array using the map method. Chaining multiple map methods will always produce the same output, thanks to the Functor Laws!

Now you may ask: “as far as I know, .map can be used only on arrays, so only arrays are functors!” …wrong! You can create a Functor out of mostly any value, that’s why is so important to understand what Functors are!

Let’s implement a Functor from zero, respecting the Functor Laws:

Great, we just defined an algebra that will be our starting point!
Now, in order to make it look like a real Functor, we need to make it mappable, always respecting the Functor Laws.

Great! We just created our first mappable Functor! Let’s test it:

That’s awesome! Let’s see if it respects the Functor Laws:

  1. Does it return an unmodified functor? Yes!
  2. Are we able to map over and over it, always respecting the first law? Yes!

Functors and Objects

Object can be Functors too! And it’s easiest than you think:

Ok, that may not be so easy if you’re not familiar with immutability. So, I’ll rewrite the same function using loops to help you understand:

Great! So now that we have our Functor, let’s try it out!

Isn’t that awesome?

You just used classes! Is there a way to make it pure?

As you may know, classes in JavaScript are just functions. Given the fact that classes contains an internal state, they are not pure functions.
So is there a way to build a “pure” Functor?

Holy guacamole that’s sooooo easy! Let’s test it against a number!

Amazing! As you may already know, the following expressions are equivalent:

Why should I care about Functors?

Functors are a key topic in both mathematics and computer science.
Without understanding Functors, we won’t be able to understand Monads and other amazing things.
Functors adds some kind of safety in our program, just think how predictable our output can be.
They are also an awesome abstraction which enables you to work on a certain way on any datatype. Remember undefined and null? Functors makes them safe:

So as you can read, we can only apply certain functions when a value is known (so not undefined or null).

Conclusion

So, in few words, a Functor is a thing we can map over. If you’re familiar with category theory, you may have noticed that a Functor maps from category to category.
A Functor which maps from category back to the same category is called Endofunctor (for instance, a monad is an endofunctor).

I really hope that Functors aren’t a mystery anymore!