Kostiantyn Synyshyn
JS engineer
Nature of composing
One billion $ mistake.
What is composition anyway?
Functors & Monads.
Brief history
Sir Charles Antony Richard Hoare
I call it my billion-dollar mistake. It was the invention of the null reference in 1965.
~ Tony Hoare
const getValue = ({value}) => value;
const value = getValue(null); //=> Cannot read property 'value' of null
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"
const toUpper = string => {
if (string != null) {
// --------------
// \
// null guard
return string.toUpperCase()
}
}
const toLower = string => string && string.toUpperCase()
// ----------------
// \
// null guard
Code instantly becomes verbose
const selectPartnerLogos = createSelector(
selectContent,
content => content && content.sideInfo && content.sideInfo.bottomImages
);
const getNestedProperty = obj => obj && obj.prop && obj.prop[0];
Functions lose their essence
Well...
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
const promise = Promise.resolve(888);
const maybe = Maybe(888);
promise.then(double); :: -> Promise
maybe.map(double); :: -> Maybe
You're already familiar with an API
const Box = x =>
({
map: f => Box(f(x)),
flat: f => f(x),
})
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);
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
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:
const compose = (f, g) => x => f(g(x));
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);
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?
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));
Mapping
Procedures
I/O
They are idempotent
They offer referential transparency
They are memoizable
They can be lazy
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.
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
Maybe
Nothing
Just
Nothing
Maybe
N
J
Nothing
N
M
Simple Maybe usage example
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
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
Composable
Reusable
Independent
Concise
Simple
Learn to recognize characteristics of good abstractions:
Thank you!
Q&A
By Kostiantyn Synyshyn
intro to functional programming