JavaScript Jems -  Functional And Not Quite Functional
Written by Mike James   
Monday, 07 December 2020
Article Index
JavaScript Jems -  Functional And Not Quite Functional
Functional Programming In Javascript

JavaScript's functional programming is initially very attractive, but if you slide into using it, you might be shocked at how difficult it is to be "hardline functional". This is an extract from my 2020 book, JavaScript Jems: The Amazing Parts.

Now available as a book from your local Amazon.

JavaScript Jems:
The Amazing Parts

kindlecover

Contents

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

Jem 16 Functional And Not Quite Functional

Whoever said that pleasure wasn't functional?”

Charles Eames

Functional programming is a programming paradigm that has a gained a great deal of popularity recently and JavaScript can be used in a functional style. This isn't surprising as it was inspired by the functional language, Scheme. However there are "degrees" of functional programming depending on how strict you want to be in applying its basic principles.

Most programmers who adopt a functional style don't go the whole way and essentially make use of the easy and rewarding parts of the idea. This isn't necessarily a bad thing, but it does leave you open to criticism that you don't really know what functional is - so let’s put that right.

The Essence of Functional Programming

Functional languages try to reduce, or is it enhance, programming languages to mathematical functions. That is, when you use a mathematical function its result never changes - the result of sin(0.3) is always the same - and a function is just a lookup table. Sometimes the lookup table is too big to be stored and in this case the result is returned after being calculated using a procedure - but in theory all mathematical functions can be implemented as lookup tables. Converting a function that produces a result by calculation into one that stores the results in a lookup table is often referred to as memoization.

That is, mathematical functions provide a way to do computation without any dynamic change. A function returns its result and it is the same result for the same input. It is static and stateless.

This isn't so with the procedural programming meaning of functions or procedures. In the programming context, a function is just a procedure that returns a single value as its result. All procedures can be cast as functions by the simple trick of having them return a single, but perhaps complicated structure, containing all their results rolled up into one object. That is, in general, a function can accept and return objects including other functions.

This is usually expressed as functional programming needs "first class functions". Of course, in JavaScript functions are just objects that can be invoked using the invocation operator () - so they are first class by default. It is also common to call a function that accepts or returns another function a "higher order function".

A programming function can produce “side effects“ and state changes, for example:

function addone(){
 globalvariable=globalvariable+1;
 return globalvariable
}

In this case each time the function is called it returns a new value - it is counting - it is procedural - and this can't be allowed in a functional language. In addition, it changes a global variable and this is a side effect. If another function makes use of the same global then its behavior will have been changed.

A function that gives the same result every time it is called with the same parameters and one that has no side effects is called a pure function. The goal of functional programming is to use nothing but pure functions.

In a functional language the sort of counting described above isn't allowed and variables aren't variable in the sense that once defined they have that value for the duration of the program - they are "bound" to their value. In other words, all objects are immutable. Once created an object cannot be changed.

At this point non-functional programmers generally give up because this is nothing like the way they think. How can there be loops and conditions if variables never change? How can the counting function be implemented in a pure way with immutable objects?

There are two answers to this question. The first is why are you counting at all? If the counting is part of an algorithm that gets you to a solution then don't do it - simply get the solution. That is, if you implement sin(0.3) with an iterative calculation, simply hide the iteration behind the function and return the result. In other words pretend that there is no iteration involved and leave it to hidden non-functional implementations.

The second answer is that there are functional ways of doing the same job, mostly recursion and functional composition. For example, if f(x) is a function which returns x+1 then counting can be implemented as:

x=0;
y=f(x);
z=f(f(x));

and so on...

Notice that in the set of nested functions:

z=f(f(f(f(f(f(f(x)))))));

only one variable z is bound to the result, no variables change their values and yet even so there is still an "increment" as you work your way into the brackets.

This is how pure functions can be used to count. In principle the function does something with the count, much as you would in a for loop say. This is, the functional language’s equivalent of the fixed repeat for loop. There are also equivalents of for loops that perform variable numbers of repeat using either functional composition or recursion.

For example, if you want to count down from N to 0 you would use:

function count(N){ 
   if(N===0)return;
   count(N-1);
}

Notice that as N is used as a parameter its value isn't changed as a new N comes into existence each time the function is called. Some programmers take to recursion and some don't. Recursion is natural for some problems and less so for others. Notice that this is a pure function, but if you put an ??alert in the body to display the count it has a side effect and is no longer pure.

So the main principles of functional programming are:

 

  • First class functions – for function composition and higher order functions.

  • Pure functions - functions always return the same output for the same input and have no side effects.

  • Immutable data - data is never changed once created and new data is created in place of mutation.

  • Recursion is a natural way of avoiding mutating data and provides an alternative to iteration.

 

How strictly these are obeyed varies a great deal and you can program in a way that is slightly functional, mostly functional or hard line, that is nothing but functional styles. In many cases programmers opt to take the immediate advantages of functional programming by using first class functions, functional composition and higher order functions, but tend to be less concerned about avoiding side effects, allowing mutable data and using recursion.



Last Updated ( Monday, 07 December 2020 )