Functional programming contains a set of very compelling techniques that drive your application’s control and data flow. Pure functional programs have many of these techniques built into them, such as automatic currying (which we’ll see in a bit). Unfortunately, JavaScript doesn’t. Now, this doesn’t mean you can’t use JS functionally. In fact, because JavaScript has support for closures and high-order functions, you can very easily extend the platform via functional libraries to support all of the most important functional techniques you’ll need.
Away with loops!
A noticeable quality of functional programs is the absence of the standard looping mechanisms: for, while, and do-while. The reason here is that pure functional programs don’t mutate variables (like a loop counter) after they’ve been initialized. Instead, we will take advantage of high-order functions—like: forEach, map, reduce, and filter—to abstract iteration schemes, which also help us remove a few if-else conditionals while we’re at it. JavaScript has native implementations of these functions, but it’s worth considering the implementations provided in the library Lodash.js, as they are more extensible.
You can download Lodash.js here: https://lodash.com.
Lodash.js defines a global object wrapper _ (an underscore), which can be used to unlock all of its functionality, starting with _.forEach:
_.forEach
This function iterates over the elements of a collection, invoking the provided iteratee function on each one. The callback function is supplied 3 arguments: value, index, and array.
_.foreach([80, 90, 100], function(value) {
setTimeout(function() {
console.log(value);
}, 100);
}).value();
Aside from not having to keep track of loop counters and array length, _.forEach also makes your code more declarative and easier to understand. Also, because the body of the loop is encapsulated inside a function, it properly binds each loop value into the callback’s parameter, avoiding some of those nasty scoping JavaScript bugs.
_.map
Mapping functions onto containers is an important part of functional programming. For arrays, I can use a mapping function to transform its contents into an array of similar length as the original, while keeping the original intact. The _.map function also has the built-in feature of skipping nulls, so it saves us from having to manually do if-else null checks.
The function supplied to _.map is invoked with the same arguments as _.forEach. Given a function:
var toLetter = function (grade) {
if(grade >= 90) return 'A';
if(grade >= 80) return 'B';
if(grade >= 70) return 'C';
if(grade >= 60) return 'D';
return 'F';
};
We can transform a list of numerical grades into letter grades:
_.map([20, 98, 100, 73, 85, 50], toLetter);
//-> [F, A, A, C, B, F]
_.filter
Filter transforms an array by mapping a predicate function (function with a boolean return value) onto each element. The resulting array is made up of, potentially, a subset of elements for which the predicate returns true.
_.filter(['Spain', 'USA', 'Serbia', 'Uganda'], (name) => name.substring(0,1) === 'S');
//-> [Spain, Serbia]
The function supplied to _.filter has the same arguments as _.map. As you can see from the code above, _.filter abstracts the task of performing an if-else check to remove elements from the array, where the condition clause is encoded as the predicate function.
_.reduce
Typically used as a terminal operation originating from _.map, _.reduce can be used to fold or gather the contents of an array by compressing it into a single value. Each successive invocation is supplied the return value of the previous. _.reduce is typically seen as combined with _.map and _.filter:
The accumulator function is supplied the current running total (or accumulated value), the current value, index, and the array.
Map, reduce, filter exercise: http://jsbin.com/cihuyo/edit?js,console.
Function Chaining
Functions like map, filter, and reduce are just a few of an entire library of functions in Lodash. In fact, all functions in Lodash are designed to be chainable, starting with _.chain():
var users = [
{ 'user': 'Haskell', 'birth': 1900 },
{ 'user': 'Turing', 'birth': 1903 },
{ 'user': 'Rosser', 'birth': 1907 },
];
var youngest =
_.chain(users)
.sortBy('birth') .last()
.value(); //-> Rosser
Chaining functions this way leads to very declarative code, which describes what the program should do rather than how it does it. Function chains allow you to describe the parts of your application without actually running it. Only when the last function _.value() is invoked does evaluation actually occur.
Recursion
Recursion has many uses in software, especially when solving self-similar types of problems such as traversing trees or mathematical progressions like Fibonacci. It turns out recursion can also be extremely effective at traversing any type of sequential data structures such as arrays, which is why it’s become the de facto iteration mechanism in functional languages.
Traversing arrays recursively originates from realizing arrays are self-defined as collections, each having a head and a tail, both available as Lodash operations. Here’s a quick example of a sum function to add all of the elements in an array.
function sum(arr) {
var list = _(arr);
return list.isEmpty() ? return 0 :
list.head() + sum(list.tail());
}
sum([]); //-> 0
sum([1,2,3,4,5,6,7,8,9]); //->45
The main benefit of recursion is that you can loop in an immutable manner since there’s no explicit loop counter to update. Hence, the responsibility of moving through the elements in an array is ceded entirely to the language runtime.
Function Abstractions
Functional programming provides very powerful abstractions that allow you to create functions from the definition of other functions or to augment the evaluation of existing functions. The first abstraction we’ll talk about is _.curry.
Currying
Currying is a technique that converts a multivariable function into a step-wise sequence of unary functions. In other words, a function with parameters: f(a,b,c) is internally augmented toonethatworksonparametersoneatatime: f(a) -> f(b) -> f(c). Consider the case of a function name that returns first and last name:
// name :: String -> String -> String
var name =
function (first) {
return function (last) {
...
Instead of writing it like this, we can use Lodash’s automatic currying functionality:
var name = _.curry(function(last, first) {
return [last, first].join(',');
});
// When supplied both arguments, it evaluates the function immediately
name('Curry')('Haskell'); //-> 'Curry, Haskell'
// When supplied one argument, it returns another function
name('Curry'); //-> Function
As you can see from the example above, name is a function of two arguments. From this curried version, a family of functions is born by partially applying only the first argument:
var curry = name('Curry');
curry('Haskell'); //-> 'Curry, Haskell'
curry('Samuel'); //-> 'Curry, Samuel'
curry('Anna'); //-> 'Curry, Anna'
Currying exercise: http://jsbin.com/dubaqa/edit?html,js,console.
This idea of partially applying arguments has another modality, known as partial application.
Partial Application
Partial application is an operation that binds a subset of a non-variadic function’s parameters to fixed values, creating a function of smaller arity. This is especially useful when implementing presets or default function arguments. Consider the following log function:
function log (level, target, message)
I can use this function to log a message with different levels and target either the console or an alert box. Using _.partial, I can create an infoConsoleLogger, for example:
var infoConsoleLogger = _.partial(log, 'console', 'INFO');
infoConsoleLogger('Users name ' + name('Curry', 'Haskell'));
Partial application can also be used with placeholders (_) to extend language with native behavior. Consider these two examples:
// Take the first N characters of a String
String.prototype.first = _.partial(String.prototype.substring, 0, _);
'Functional Programming'.first(3); //-> 'Fun'
// Convert any name into a Last, First format
String.prototype.asName = _.partial(String.prototype.replace, /(\w+)\s(\w+)/, '$2, $1');
'Alonzo Church'.asName(); //-> 'Church, Alonzo'
Both currying and partial application are extremely useful when combined with composition.
Composition
Composition is the process used to group together the execution of simpler functions. In essence, composition is a function derived from other functions.
The composition of 2 functions g and f (read f composed of g) is given by:
f · g = f(g) = compose :: (B -> C) -> (A -> B) -> (A -> C)
You can visualize the composition of two functions as a mapping of sets linking their inputs and outputs:
In simple terms, this means the output of g will be passed into the input of f. Let’s see this in action using Lodash’s _.compose:
var str = "We can only see a short distance ahead but we can see plenty there that needs to be done";
var explode = (str) => str.split(/\s+/);
var count = (arr) => arr.length;
var countWords = _.compose(count, explode); //-> 19
Because functions have single return values, it’s imperative for the function receiving the input (in this case f) to behave as a unary function. This is where currying is so useful, as it can be used to reduce a function’s parameters to one. Let’s expand on the example shown previously; this time we will determine if a block of text contains 10 words:
var check = _.curry((len, size) => size >= len);
var check10 = check(10);
var checkText = _.compose(check10, count, explode);
checkText(str); //-> true
Currying and composition exercise: http://jsbin.com/fokixa/edit?html,js,console.
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}