Functors are closed under composition. This means that we should be able to construct a well-behaved map
method for the composition.
Functors are closed under composition. The term closed means that if we have two functors and we compose them (have a functor-in-a-functor situation like Maybe<Id<>>
or Maybe<Array<>>
, Array<Array<>>
etc), the resulting structure is also a functor.
This means that we should be able to construct a well-behaved map
method for the composition, using only the map
methods of the composing functors and nothing more.
Let us examine some specific cases. We will start with the Id<Array<>>
case. This is not a Type that you will see in practice but will make the mechanics easier to examine. It’s easy to get a Id<Array<>>
. For example we can place some Clients in an Id<>:
Id([new Client(1, "jim", 2), new Client(2, "jane", 3)])
now we can define a map for this composition easily
var mapT = composite => f => composite.map(inner => inner.map(f))
import { Client } from "./model.js" import { Id } from "./Id.js" let idClients =Id([new Client(1, "jim", 2), new Client(2, "jane", 3)]) ; let mapT = composite => f => composite.map(inner => inner.map(f)) let idNames = mapT(idClients)(client=>client.name) console.log(idNames) //Id (['jim', 'jane' ] ) //the result is an Id<Array[String]> // -An Id of an Array of Strings
Run This
You will use the map of each Functors to pass the function client=>client.name
one level deeper.
It’s easy to see that this pattern .map(_->_.map(_->_))
will appear in any combination of functors. Look at another combination just to confirm this. For an Array<Array<>>
import { Client } from "./model.js" let groupsOfClientsByDepartment = [ [new Client(1, "jim", 2), new Client(2, "jane", 3)], [new Client(3, "kate", 2), new Client(4, "John", 3)]]; var mapT = composite => f => composite.map(inner => inner.map(f)) var groupsOfClientNamesByDepartment = mapT(groupsOfClientsByDepartment)(client => client.name) console.log(groupsOfClientNamesByDepartment) //[ [ 'jim', 'jane' ], [ 'kate', 'John' ] ] //the result is an Array<Array[String]> // -An Array of an Array of Strings
It is the same .map(_->_.map(_->_))
pattern again.
Transformer Types
Another way to express this composition is by creating an adapter that we usually refer to as “transformers” that would expose a single .map(_)
export const ComposeT = composition => ({ map: f => ComposeT(composition.map(inner => inner.map(f))), unwrap: () => composition });
we can use this IdArrayT
transformer in the following way :
The main computation now becomes :
let idNames = ComposeT(idClients) .map(client => client.name) .map(name => name.toUpperCase()) .unwrap();
*In the next sections we are going to use those ideas to deal with the Promise<Maybe<>>
and Promise<Either<>>
combinations.
Excerpt from the free course https://www.fluidinfunctional.com/jscourse/ which is a self-standing subset of the book “Functional Programming in Javascript”
https://www.fluidinfunctional.com/jscourse/
Top comments (0)