dimitris papadimitriou
dimitris papadimitriou More than 12 years’ experience as full stack developer and Software Architect . Functional javascript with categories.

Functor Properties

Functor Properties

Functor Properties

Functors should Commute

There is one important thing about the mapping function. If you look the following diagram you will see that there are two ways to reach from an integer value of 2 to an Id(4) having a squaring function x=>x*x

The map should get the same result for Id(4) no matter which of the two possible routes to get there we take. This means map should preserve the structure

  1. We could first apply the squaring function on the 2 and then get the Id() of the result. This is the blue path of the diagram.
1
 var id4 = Id(f(2));
  1. Or, we could first get the Id(2) and then use map to get the Id(4). This is the red path on the diagram.
1
 var id4 = Id(2).map(f);

When those two paths always return the same result, then we say the diagram commutes

The Functor Laws

Additionally, any functor .map() method must obey two basic laws:

  1. Firstly the functor mapshould preserves the Identity. This simply means that when we map the id function x=>x nothing happens to the Functor.
1
2
3
4
5
 import { Id } from "./Id.js"
// Law 1-identity preserving fmap id = id
var id = Id(4).map(x => x); //mapping with the x=>x leave everything as it is 

console.log(id);
  1. Secondly, the map should preserve the composition of functions F(f○g) = F(f) ○ F(g)
1
2
3
4
5
6
7
8
9
10
11
12
13
 import { Id } from "./Id.js"

// Law 2 composition of functions is preserved    
// Id.map (f . g)  ==    Id.map(f) .   Id.map (g)

var value = 2

var f =x=>x*x;
var g =x=>3*x;

console.log(Id(value).map(x=>g(f(x))))   //map (f . g) - applying the map on the composition 

console.log(Id(value).map(f).map(g)) ;   //map f . map g - applying the functions sequentialy using map  

Run this

his second law is the reason why we can replace function composition with map chaining because those two properties are equivalent. In the following example you can see that using the fluent map the Id functor provides

1
Id(client).map(getName).map(toUpperCase).getValue()

is the same as using the function composition on the client value:

1
toUpperCase(getName(client))

Run the following script to see that effect in action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Id } from "./Id.js"
import { Client } from "./Client.js"

var getName = client => client.name;
var toUpperCase = name => name.toUpperCase();
var composition = client => toUpperCase(getName(client));

var client = new Client(1, "jake");

//all the following are equivalent : 
console.log(composition(client)) 

console.log(Id(composition(client)).getValue());
console.log(Id(composition(client)).map(x => x).getValue());
console.log(Id(client).map(composition).getValue());               //F(f○g) 
console.log(Id(client).map(getName).map(toUpperCase).getValue());  //F(f) ○ F(g)
console.log(Id(client).map(composition).map(x => x).getValue());   //F(f○g) ○ 1

Run this

We are not going to expand on this any further, but feel free to think about how the code relate to the diagram above.

comments powered by Disqus