Next

1. First-class functions

A necessity for functional programming is the concept of first-class functions. Functions are first-class citizens of a language if they can be:

stored

passed as argument

returned

JavaScript is one of many languages which consider functions to be just another kind of object and allow their assignment:

constsquare=x=>x*x;// square(2) = 4

Or to pass them as argument to other functions:

consttwice=f=>x=>f(x)+f(x);// twice(square)(2) = 8

The constant twice takes a function f and returns a function which takes an argument x and applies f to x. This is done separately two times and then the two results are summed up. Interestingly, in a non-functional context this is might not always be equivalent to doubling the result of a function.

What are the advantages of using first-class functions?

First-class functions remove layers of indirection which would result in visual/cognitive strain and maintenance complexity.

// IndirectionconstController={create:args=>Db.create(args)};

The explicit wrapping in another function is unnecessary. We can pass the function like any other object to be executed later:

// Without indirectionconstController={create:Db.create};

First-class functions allow the maintenance of the application to become less complex since refactoring happens in one place.

// IndirectiongetPost('/api/post',json=>renderPost(json));

If we need to add another parameter, we need make a change in two places:

// RefactoringgetPost('/api/post',(json,err)=>renderPost(json,err));

Using the same technique as above, passing the function as object, we move the parameter definition to the implementation:

// BettergetPost('/api/post',renderPost);

First-class functions minimize naming issues which are introduced by coupling to a specific naming. Subjectivity, competence or changing requirements often introduce misnomers.

The code above is specifically tied to a certain domain where it doesn’t have to be.

// Abstractconstcompact=xs=>xs.filter(x=>x!==null&&x!==undefined);

xs being the plural of x which is common in functional languages, e.g. Clojure.

2. Pure functions

Mutable state is probably the number one reason for software complexity [Moseley & Marks 2006]. However state is a necessity therefore it has to be encapsulated. Pure functions help you to reduce the complexity since it is self-contained and specifies everything it needs to produce a result:

// Pureconstabove=(n,limit)=>returnn>limit;

Therefore functions that rely on external state are not pure:

// Impureletlimit=0;constabove=n=>returnn>limit;

Given the same input it always returns the same output without observable side effects:

Described in this way, a programmatic function becomes identical to the mathematical definition of a function and can be understood as a mapping from one value to another, e.g. the values [1, 2, 3] could be mapped to [2, 3, 4] with:

constaddOne={1:2,2:3,3:4};

Indeed the function f(x) = x + 1 is just a convenience.

What are the advantages of using pure functions?

Given the example:

constsignUp=(db,credentials)=>{...};

Pure functions are self-documenting via signature.

Everything required to sign up a user is clear by the signature alone, you need a database for persistence and the credentials to persist.

Pure functions are flexible due to parameterization.

We have all dependencies as parameters and the implementation details of the database are irrelevant.

Because a pure function is deterministic, we can replace it with its evaluated value. In fact, if our program would only consist of pure functions, we could mathematically proof its behavior and result.

On a smaller scale however, this becomes also handy in smaller chains of pure functions which are easier to refactor since you can reason about them a lot easier.

Pure functions are parallelizable.

They don’t have shared memory and therefore can’t have a race condition.

3. Currying

Currying is the technique to translate a function with n arguments into n functions with one argument. The terminology is to say that the arity is reduced to one:

Arity: The number of arguments a function takes.

// Uncurriedconstadd=(x,y)=>x+y;// Curriedconstadd=x=>y=>x+y;

There are libraries which can help to create curried functions like lodash.curry and functional libraries like lodash/fp or Ramda provide curried functions by default.

Advantages of currying?

Currying enables syntactical conciseness and expressiveness.

Unfortunately, it is extremely difficult to find simple examples that convey the advantages of currying.

With growing complexity, the usefulness of currying increases, especially if you use a library like React with higher-order components or just plain higher-order functions.

You can create a specific function from an abstract one with no cost at all.

Bonus: Partial Application

Often confused with currying, partial application is the pre-filling of some arguments to create a new function. Curried functions are therefore always partially applied. For the example we use lodash’s _.partial method to enable placeholders: