Say NO to Loops

In functional programming languages, there are no loops. When you need to do an operation like traversing a list or a tree, there are two predominant styles: recursion and higher order functions.

Recursion relies on a function calling itself, usually on a different part of the parameter (list being traversed for example). That’s a topic for another post.

Higher order functions are usually provided by the language. In ES6 JavaScript these functions are defined on the Array prototype.

Array#map

map is used if we want to perform the same change on each member of the array. It takes the function that should be applied to each element of the array as a parameter. That function is passed (element, index, wholeArray)as parameters.

const myArr = [ 'some text', 'more text', 'final text' ];
const mappedArr = myArr.map( function(str) {
  return str.split(' ');
});
console.log(mappedArr);
// [ [ 'some', 'text' ], [ 'more', 'text' ], [ 'final', 'text' ] ]

Array#filter

filter allows us to pick which elements of the array should remain in the transformed list by passing a filtering function that returns a Boolean value (true/false). As for map this functions is passed (element, index, wholeArray).

const myArr = [ 5, 10, 4, 50, 3 ];
const multiplesOfFive = myArr.filter( function(num) {
  return num % 5 === 0;
});
console.log(multiplesOfFive);
// [ 5, 10, 50 ]

Array#reduce

reduce is used to change the shape of the array. We provide more than 1 parameter to this function (in addition to the array we’re reducing). We pass a reducing function and optionally the initial value of to reduce with. The function is passed (prev, curr, index, wholeArray) . prev is the value returned by the previous reduction, for the first iteration that means it’s either the initial value of the first element of the array. curr is the value in the array at which we’re at.

The classic example is summing or concatenating.

const myNumbers = [ 1, 2, 5 ];
const myWords = [ 'These', 'all', 'form', 'a', 'sentence' ];
const sum = myNumbers.reduce( function(prev, curr) {
  return prev + curr;
}, 0);
console.log(sum); // 8
const sentence = myWords.reduce( (prev, curr) => {
 return prev + ' ' + curr;
}); // the initial value is optional
console.log(sentence);
// 'These all form a sentence'

If you want to learn more about the internal of mapfilter and reduce or recursion, I’ve reimplemented them in a recursive style using ES6 destructuring in the following post:

Higher order functions in practice

No more loops

Higher order functions allow us to get rid of the imperative loops that seem to be spread everywhere.

var newArr = [];
var myArr = [ 1, 2, 3 ];
for(var i = 0; i < myArr.length; i++) {
  newArr.push(myArr[i] * 2);
}
console.log(newArr); // [ 2, 4, 6 ]
// nicer with `map`
const doubled = myArr.map( x => x * 2 );
console.log(doubled); // [ 2, 4, 6 ]

The intent is just clearer with map. We can also extract the double function so we’re making our code more readable and modular.

const double = x => x * 2;
const doubled = arr.map(double);

It reads like a book and that’s important because we write for humans not machines.

Side-effect free programming

Array higher order functions do not mutate the variable they are called on. This is good, because the loop-based approach using .push and .popchanges it. It means if you pass a variable as a parameter, it’s not suddenly going to get changed by a function down the call stack.

// some random module
// obviously no one actually does this
function doesBadSideEffect(arr) {
  return arr.pop();
}
// somewhere quite important
var arr = [ 'a', 'b', 'c' ];
var joinedLetters = '';
for(var i = 0; i < arr.length; i++) {
  joinedLetters += arr[i];
  doesBadSideEffect(arr)
}
console.log(joinedLetters);
// whoops 'ab'
// even though the naming makes us
// expect 'abc'

Declarative Code Optimisations

In some languages functions like map are parallelised. That’s because we don’t actually need to know what’s in the rest of the array to compute this particular element’s new value. If we’re doing complex things in the

 

ref: https://hackernoon.com/effective-functional-javascript-first-class-and-higher-order-functions-713fde8df50a

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s