Nature of composing

Table of contents

  1. One billion $ mistake.
  2. What is composition anyway? 
  3. Functors & Monads.

 

Brief history

Sir Charles Antony Richard Hoare

One billion $ mistake

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. 

~ Tony Hoare

Do not underestimate NULL

const getValue = ({value}) => value;
const value = getValue(null);  //=> ​​Cannot read property 'value' of null​​

 NULL & UNDEFINED

  • null is an object that is a assigned where the null value is a member of every type, defined to have a neutral behaviour that has no value
  • undefined is the evaluation of a variable or value that has been declared but not yet been assigned

 

typeof null
>"object"

typeof undefined
>"undefined"

null == undefined
>"true"

NULL guards 

const toUpper = string => {
  if (string != null) {
//    --------------
//                   \
//                    null guard
    return string.toUpperCase()
  }
}

const toLower = string => string && string.toUpperCase()
//                         ----------------
//                  		\
//                    		null guard
Code instantly becomes verbose

NULL guards 

const selectPartnerLogos = createSelector(
  selectContent,
  content => content && content.sideInfo && content.sideInfo.bottomImages
);


const getNestedProperty = obj => obj && obj.prop && obj.prop[0];
Functions lose their essence 

Is there a solution for it?
 

Well...
Maybe?

The Maybe 

// creating safe value
const safeVal = Maybe(3);


// pure functions
const threeeTimes = x => x * 3;
const inc = x=> x + 1;

// Maybe usage
safeVal
    .map(inc)          :: Maybe -> Maybe
    .map(threeTimes)   :: Maybe -> Maybe
    .flat(console.log) :: value

Maybe example 

const promise = Promise.resolve(888);
const maybe = Maybe(888);

promise.then(double); :: -> Promise
maybe.map(double); :: -> Maybe
You're already familiar with an API

Let's implement it

 

The Box

 

const Box = x =>
({
  map: f => Box(f(x)),
  flat: f => f(x),
})

The Array example

 

const value = Array.of(5, 6, 7);

const result = value
.map(x => x * 2)
.filter(x => x > 10);
console.log(result);

const ArrayBox = new Maybe([5, 6, 7]);
ArrayBox
.map(map(x => x * 2))
.map(filter(x => x > 10))
.fold(arr => console.log(arr);

 The most important

cosnt getElemById = id => document.getElementById(id);
const prop = prop => obj => obj[prop];
const toUpperCase => string => string.toUpperCase();

const capitalize = compose(
       	toUpperCase, // String -> String
        prop('textContent'), // Object -> String
        getElemById // String -> DOMElement
    )('myDomEl');
It let's you compose

Composition

The act of breaking a complex problem down to smaller parts, and then composing those smaller solutions together to form your application.
Function Composition is the application of one function to the result of another:
(f∘g)(x)=f(g(x))
const compose = (f, g) => x => f(g(x));

Compose properly & reduce complexity

const increment = x => x + 1;
const double = x => 2 * x;
const square = x => x * x;


const incThenDoubleThenSquare = compose(
square,
double,
increment
);

const result = [5].map(incThenDoubleThenSquare)  // [144]
const compose = (...fns) => x => fns.reduceRight((y,f)=> f(y), x);
const pipe = (...fns) => x => fns.reduce((y,f)=> f(y), x);

Theory of categories

A category consists of a collection of nodes (objects) and morphisms (functions). An object could be numbers, strings, urls, customers, dogs or any other way you wish to organize like-things. (a, b, and c in the graphic are the objects.)
What is a FUNCTION?

Function - main building block

Functions possess the properties that are essential for a good abstraction:
  • Identity - The ability to assign a name to it and reuse it in different contexts.
  • Composable - The ability to compose simple functions to form more complex functions.
// anonymous functions are assigned to variables
const increment = x => x + 1;
const double = x => 2 * x;

// simple function composition
const doubleThenInc = x => inc(double(x));

Functions are here to serve

  • Mapping
  • Procedures
  • I/O

Pure functions

  • They are idempotent
  • They offer referential transparency
  • They are memoizable
  • They can be lazy

Morphism examples

const arrayToLength = array => array.length;
const floatToInt = num => num | 0;
const rawDataToJson = data => data.json();
const urlToData = url => fetch(url).then(rawDataToJson);
Map is a function to convert something from one object to another.   A map between objects is a Morphism.

Back to the Maybe type

const Maybe = x => (x != null ? Just(x) : Nothing(null));

const Just = x => ({
  map: f => Just(f(x)),
  fold: (f, g) => g(x)
});

const Nothing = x => ({
  map: f => Nothing(x),
  fold: (f, g) => f(x)
});

Text

The Maybe flow

Maybe
Nothing
Just
Nothing
Maybe
N
J
Nothing
N
M
Simple Maybe usage example

Functor

Functor data type is something you can map over between objects in category.

 

const arr = [1, 2, 3];
const double = x => x * 2;
const doubledArr = arr.map(double);

Dead easy

Why functors?

The details of the underlying data structure implementation are abstracted away. ( incl. arrays, streams, trees etc.)

Functors hide the types of the data they contain, which allows you to act on the containers using generic functions.

Mapping over an empty functor (incl. null )is the same as mapping over a functor containing many items.

Most importantly, functors allow you to easily compose functions over the data inside

Some useful info

Links

Summary

 
  • Composable
  • Reusable
  • Independent
  • Concise
  • Simple

Learn to recognize characteristics of good abstractions:

 

Thank you!

Q&A

Nature of Composing

By Kostiantyn Synyshyn

Nature of Composing

intro to functional programming

  • 27