Functional Programming

Omit needless names

Functions have to get its input from the arguments to make them predictable. If they pull in data from other resources during their
process, then it becomes very difficult to mock those hidden inputs for testing.

http://output.jsbin.com/yoyip

  1. // Bad practice
  2. function daysThisMonth () {
  3. var date = new Date(),
  4. y = date.getFullYear(),
  5. m = date.getMonth(),
  6. start = new Date(y, m, 1),
  7. end = new Date(y, m + 1, 1);
  8. return (end - start) / (1000 * 60 * 60 * 24);
  9. }
  10. // Good practice
  11. function daysInMonth (y, m) {
  12. var start = new Date(y, m - 1, 1)
  13. , end = new Date(y, m, 1);
  14. return (end - start) / (1000 * 60 * 60 * 24);
  15. }

Separate mutation from calculation.

Functions should be so specific that they can be easily unit tested without having to do complex mocks.

Pure Functions

Functions that don’t change anything, they just compute and return a result.
Characteristics:

  • easy to unit test
  • portable: can be used on client and on server
  • memoizable: it caches the results so its faster the next time they run the function with the same input.
  • parellalizable: you can run them in parallel with other functions since they won’t mutate anything.
  • The dependencies and inputs must be pure too, otherwise it will pollute the function. (eg. injecting a console through the arguments to be able to do console.log).

Separate Functions from Rules

A function is a single-valued collection of pairs. For each input (domain) case there will be only one outcome (range) and will always be the same.

e.g.

domain range
-2 -1
0 0
2 1

Arity

Arity - The ability to accept n amount of arguments.

  • Nullary
  • Binary
  • Ternary
  • n-ary
  • variable arity

Currying

Function to curry

  1. function curry(fn) {
  2. return function() {
  3. if(fn.length > arguments.length) {
  4. var slice = Array.prototype.slice;
  5. var args = slice.apply(arguments);
  6. return function() {
  7. return fn.apply(
  8. null, args.concat(slice.apply(arguments))
  9. );
  10. }
  11. }
  12. return fn.apply(null, arguments);
  13. };
  14. }

Ramda - Curry library way better than underscorejs or lowdashjs

Curry example

  1. function curry(fn) {
  2. console.log('starting curry with', fn);
  3. return function () {
  4. if (fn.length > arguments.length) {
  5. console.log('if fn.l > a.l');
  6. var slice = Array.prototype.slice;
  7. var args = slice.apply(arguments);
  8. console.log('args');
  9. console.log(args);
  10. return function () {
  11. return fn.apply(
  12. null, args.concat(slice.apply(arguments)));
  13. }
  14. }
  15. console.log('arguments', arguments);
  16. return fn.apply(null, arguments);
  17. };
  18. }
  19. // We've got a nice multiply function.
  20. // It takes two arguments.
  21. function multiply(a, b) {
  22. console.log('multiplying', a, b);
  23. return a * b;
  24. }
  25. // But it has been secretly curried already
  26. // so we can feed it fewer arguments and it
  27. // will return a new function.
  28. var curryMultiply = curry(multiply);
  29. // How about making a function to double a
  30. // value? Done.
  31. var double = curryMultiply(2);
  32. console.log(double(5)) // 10

Easier currying

  1. // Example without currying
  2. let dragons = [
  3. {name: 'fluffykins', element: 'lightning' },
  4. {name: 'noomi', element: 'lightning' },
  5. {name: 'karo', element: 'timewarp' },
  6. {name: 'doomer', element: 'fire' },
  7. ]
  8. let hasElement = (element, obj) => obj.element === element;
  9. let lightningDragons = dragons.filter(x => hasElement('lightning', x))
  10. console.log(lightningDragons)
  11. // [ {name: 'fluffykins', element: 'lightning' }, {name: 'noomi', element: 'lightning' },]
  12. // make it curryiable with lodash
  13. import _ from 'lodash'
  14. hasElement = _.curry((element, obj) => obj.element === element);
  15. lightningDragons = dragons.filter(hasElement('lightning'));
  16. console.log(lightningDragons)

An example without lodash

  1. let dragon =
  2. name =>
  3. size =>
  4. element =>
  5. name + ' is a ' +
  6. size + ' dragon that breathes ' +
  7. element + '!';
  8. let output = dragon('Karo')('large')('ice');
  9. console.log(output);

Composition

Is like using unix pipe

Point free

aka Argument free

The real definition of MAP

Map is not limited to iteratable objects. Map is whenever a method gets applied inside the object.

Functor

An object or structure you can map over

If it has a map function, it is a functor

Maybe Functor

  1. var _Maybe.prototype.map = function(f) {
  2. return this.val ? Maybe(f(this.val)) : Maybe(null);
  3. };
  4. map(capitalize, Maybe(null));
  5. // => Maybe(null)
  6. // eg
  7. var firstMatch = compose(first, match(/cat/g));
  8. firstMatch('dogsup); // breaks
  9. // instead do
  10. var firstMatch = compoase(map(first), Maybe, match(/cat/g));
  11. firstMatch('dogsup); // => Maybe(null)

Identity functor

It is the easiest functor. Just wraps a value in a container.

Theories

Category Theory

Category Laws

You need an identity function

  1. // Left identity
  2. compose(id, f) == f
  3. // Right identity
  4. compose(f, id) == f
  5. // Associativity
  6. compose(compose(f, g), h) == compose(f, compose(g, h))

High Order Functions

Are functions that accept other functions as arguments.

Eg. [].filter()

Composition

When you pass another function to the high order function you are composing. Making a more complex function out of two simple functions. This is easier to reason about and to debug than having everything in a single function.

Reduce is awesome

Array.reduce is not only to get the sum of an array of numbers. It can also be used to compose an object.

eg. set an object of customers coming from an array of lines

  1. const output = file
  2. .split('\n')
  3. .trim()
  4. .map(x => x.split('\t'))
  5. .reduce((customers, line) => {
  6. customers[line[0]] = customers[line[0]] || [];
  7. customers[line[0]].push({price: line[1]})
  8. return customers;
  9. }, {});

Reference

  • Hardcore Functional Programming - Frontend Masters