Table of contents
Open Table of contents
Functor in Javascript
Functor is an object which implements map method on it.
- To understand Functor we must understand mathematical concept called Category. Category consists of three components.
- Objects
- Arrows or morphisms or functions
- Composition
Objects could be numbers, strings, arrays, urls or custom type objects etc. Arrows or functions are relations between Objects. map method is convert one object type to another object type. Number of functions can be composed as I have explained this concept in one of my blog post.
Now Let’s take an example and understand how Functor works
const Functor = value => ({
value,
});
const res = Functor(10); // {value: 10}
const res1 = Functor([1, 2, 3]); // {value: [1, 2, 3]}
const res3 = Functor("Hello World"); // {value: "Hello World"}
This is the way we extract value from Functor. But this is not Functor as per the definition. Because Functor is an object which implements map method on it.
Now let’s implement map method on any object type.
const Functor = value => ({
value,
map: fn => Functor(fn(value)),
});
const res = Functor(10); // now object has value and map method on it
const finalResult = res.map(data => {
return data * 2;
});
console.log(finalResult.value); // 20
Always remember Functor always returns another functor type
Monad
Monad is a design pattern that provides a structure for chaining operations together in a composable and predictable way.
Let’s take an example and understand what monad is
const Maybe = value => ({
value,
map: fn =>
value !== null && value !== undefined ? Maybe(fn(value)) : Maybe(null),
flatMap: fn => fn(value),
});
- map function always returns another Functor.
- Here flatMap is a Monad which returns value of the map function rather than functor
- So it can be helpful if we want to manipulate data
// get user data
const fetchUserData = id => {
// call api with id
// let's assume API is returning below data
return {
first_name: "Prem",
last_name: "Patel",
};
};
// get full name
const fullName = (firstName, lastName) => {
return firstName + " " + lastName;
};
// Functor and Monad
const Maybe = value => ({
value,
map: fn =>
value !== null && value !== undefined ? Maybe(fn(value)) : Maybe(null),
flatMap: fn => fn(value),
});
const res = Maybe(2);
const d = res
.map(fetchUserData)
.map(x => fullName(x.first_name, x.last_name))
.flatMap(data => {
return data;
});
console.log(d);
- If you have written this code in traditional way, you will have to handle undefined and null in every functions you have created.
- Monad is used for handling side effects a better way.