In this article, we are going to use ES6 recursion with functional programming to understand how we can implement list operations like map, reduce, filter and join.
Head & Tail
When functions are run recursively over lists, we can model those lists as a head
and a tail
.
The head is the first element of the list, and the tail is the rest.
const [ head, ...tail ] = [ 1, 2, 3, 4 ];
// head: 1
// tail: 2, 3, 4
In ES6, we can use destructuring for retrieving the tail as above.
Doing things functional, we can implement the head and tail functions.
const getHead = ([ head, ...tail ]) => head;
const getTail = ([ head, ...tail ]) => tail;
(Tail) Recursion
We can implement functions that operate over arrays using parameter destructuring and recursion, for example map function.
List
Arrays are called lists in functional programming.
Let’s start by implementing the map function in ES6.
Map
Map takes a list and a function, and returns a list containing the result of the function applied to each element of the list.
function map([head, ...tail], fn) {
if (head === undefined && !tail.length) {
return [];
} else {
return tail.length === 0 ? // highlight
[fn(head)] : [fn(head), ...map(tail, fn)];
}
}
Line 5: the tail.length === 0
checks if there is still a tail to recurse over. Otherwise, the recursion stops there.
This function can be used to test like follows:
const items = [1, 2, 3, 4];
console.log(map(items, item => item + 1));
// 2, 3, 4, 5
Next, look at how we can implement filter method.
Filter
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
function filter([ head, ...tail ], fn) {
const newHead = fn(head) ? [ head ] : [];
return tail.length ? [ ...newHead, ...(filter(tail, fn)) ] : newHead;
}
This function can be used to test like follows:
const items = [1, 2, 3, 4];
console.log(filter(items, item => item % 2 === 0));
// 2, 4
Let’s look at the reduce
method, next.
Reduce
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
function reduce([ head, ...tail ], fn, initial) {
if(head === undefined && tail.length === 0) {
return initial;
}
if(!initial) {
const [ newHead, ...newTail] = tail;
return reduce(newTail, fn, fn(head, newHead));
}
return tail.length ?
reduce(tail, fn, fn(initial, head)) : [ fn(initial, head) ];
}
Finally, let’s look at the join
method.
Join
The join() method joins all elements of an array into a string.
function join([ head, ...tail ], separator = ',') {
if (head === undefined && !tail.length) {
return '';
}
return tail.length ? head + separator + join(tail, separator) : head;
}
This function can be used to test like follows:
const items = [1, 2, 3, 4];
console.log(join(items));
// 1, 2, 3, 4
Conclusion
The functions we implemented are already in ES5 and above, but doing so in recursive functions in ES6 gives you an in-depth understanding on how to use functional programming and ES6 effectively