XenonStack Recommends

Big Data Engineering

Functional Programming in JavaScript | A Practical Guide

Navdeep Singh Gill | 16 August 2024

Functional Programming in JavaScript

What is Functional Programming?

Functional programming (abbreviated as FP) is a programming paradigm in which programs are constructed entirely of pure functions, with no shared mutable state or side effects. We express what to do rather than how to accomplish it in functional programming, which is more declarative than imperative programming.

Real-World example is Declarative programming is a type of functional programming. It means that we announce what action job we will do without defining the particular actions we take to complete it.

A way of writing applications using only pure functions and immutable values. Click to explore about, Functional Programming

The Programming Timeline

Low Level & assembly

First Compiler

Functional 

(Declarative)

OOP

Procedural (Imperative) 

1940s

1957

1958

1960s

1972

Microcontrollers

FORTRAN

Lisp -> Clojure, Scheme, etc

Simula

C

Programing Paradigms

  • Procedural Programing (COBOL, BASIC, Pascal and C)
  • Object-Oriented (Java, C++, Obj-C)
  • Functional Programing (Lisp, Clojure, Scheme)

Sum top 10 expensive things from a list of 100 most expensive things

const getTopTenSum = (expensiveStuff) => {
expensiveStuff.sort((first, second) => first.price - second.price);
let sum = 0;
for (let i = 0; i < expensiveStuff.length; i++) {
sum += expensiveStuff[i].price;
if (i >= 10) {
return sum;
}
}
};

Issues

  • sort function mutates the array.
  • The sum variable is mutable.
  • Declaring the execution flow. We specify what should be done in each step.
const getTopTenSumt = (expensiveStuff) => (
[...expensiveStuff]
.sort((first, second) => first.price - second.price)
.slice(0, 10)
.reduce((total,item) => total + item.money, 0)
);

Pure Functions

A pure function is the function which:
  • Given the same inputs and always returns the same output,
var xs = [1,2,3,4,5]

xs.slice(0,3) // [1,2,3]
xs.slice(0,3) // [1,2,3]
var xs = [1,2,3,4,5]

//not a function
xs.splice(0,3) // [1,2,3]
xs.splice(0,3) // [4,5]
xs.splice(0,3) // []
  •  Has no side-effects

Side Effects

(What we get paid for, what customers care about, they don't care about code)
A side effect is any change in the state of an application that is visible outside of the called function but not in its return value. The following are some of the side effects:
  • Logging to the console
  • Writing to the screen
  • Writing to a file
  • Triggering any external process
  • Calling any other functions with side-effects
Functional programming avoids side effects to make it easier to extend, restructure, debug, test, and maintain a program's effects.
Functional programming is a significant paradigm shift in the software world over the past 10 years. Click to explore about, Reducing Maintenance Costs With Functional Programming

Immutability

The problem with the shared state is that you need to know every shared variable's history that the function uses or changes to understand its effects.

Problem 1: In JS, arrays, stacks, and maps are all mutable.

Solution: make all data structures immutable.

const a=Object.freeze({
foo: 'Hello',
bar: 'world',
});
a.foo='Namaste πŸ™';

Output

//Error: Cannot assign to readonly property 'foo' of object Object

But frozen objects are only superficially immutable. For example, the following object is mutable:

const a = Object.freeze({
foo: { greeting: 'Hello' },
bar: 'world',
});

a.foo.greeting='Namaste';

console.log(`${a.foo.greeting},${a.bar}`); //'Namaste πŸ™ ,world!'

USE: Immutable.js by Facebook

Make all Data Structures, variables immutable and use a copy of the existing data. But this creates another problem (copies). To overcome this, we use Persistent Data Structures like trie (immutable, supports copy operations without a lot of copies).

Curry

A curried function takes several parameters one at a time, returning a function that takes the next parameter, and so on until all parameters have been supplied. At this point, the application is finished and the final value delivered.

Binary and unary functions have different shapes. These forms are crucial, just as Lego pieces must fit together.

//unary
function Increment (x) {
return x;
}

//binary
function sum(x,y) {
return x +y;
}

Functional programmers love unary function, then binary.

Reusability Through Higher-Order Functions

What is a Higher-Order Function?

Any function that takes a function as an argument returns a function, or both is a higher-order function. Higher-order functions are frequently utilized in the following applications: 

Abstract or isolate actions, effects, or async flow control using callback functions, promises, monads, etc.

Create utilities that can act on a wide variety of data types

Partially apply a function to its arguments or create a curried function for the purpose of reuse or function composition

function f(...args) {
return args;
}

function unary(fn) {
return function one(arg)
return fn(arg)
};
}

function binary(fn) {
return function two (arg1, arg2) {
return fn(arg1, args2);
};
}

var g = unary(f)
var h = binary(f)
g(1,2,3,4); //[1]
h(1,2,3,4); // [1,2]

Why do we want to curry?

We attempted to accomplish this using unary and binary functions. We lower the code's surface area; less code equals less surface area for bugs, resulting in fewer bugs. In the context of function composition, curried functions are convenient.

const add = x => y => x + y

add(3)(2)
function add(x) {
return function(y) {
return x + y;
}
}
Immutability using curry
const request = default => options => {
options = Object.assign(
{ }, defaults, options
);
return fetch(option.url, options).then(res => res.json)
}

What is a partial application?

A partial application is a function that has been applied to some of its inputs but not all of them. To put it another way, it's a function with some inputs that are fixed within its closure scope. A partially applied function has some of its arguments fixed.
const add = (num1, num2) => num1 + num2;
const add3 = partial(add, 3) [function, default value]

const partial = (fn, ...args) => {
return (...otherArgs) => {
return fn(..args, ...otherArgs)
}
Setting up Continuous Delivery Pipeline for Continuous Integration and deployment of Scala Microservices application with Jenkins, Docker and Kubernetes. Click to explore about, Continuous Delivery Pipeline for Scala Application on Kubernetes

Composition

What is software development?

Breaking down a complicated problem into more minor problems and assembling simple solutions to generate a complete solution to the complex problem

  • The act of putting together bits or elements to create a whole (general English)
  • The process of applying a function to another function's output (programing)

In algebra,

(f o g)(x) = f(g(x)) // g is evaluated first

//normal
function minus2(x) {return x - 2}
function triple(x) { return x*3 }
function increment(x) { return x + 1 }

//add shipping rate
var tmp = increment(4);
tmp = triple(tmp);
totalCost = basePrice + minus2(tmp)

//Composition (right to left)
totalCost = basePrice + minus2(triple(increment(4));

// Better version (let's create abstraction)
shippingRate(x) {
return minus2(triple(increment(x));
}

//More better
function composeThree(fn3, fn2, fn1) {
return function composed(v) {
return fn3(fn2(fn1(v))));
}

var shippingRate = composeThree(minus2, triple, increment);
shippingRate(4)

Why Functional Programing in JAVASCRIPT

Javascript supports multi-paradigm, including functional, object-oriented, procedural, and prototypal programming.

FACT: In just ten days, Brendan Eich wrote the initial version of the language that would become JavaScript.

Why does JS support multiple paradigms?

Brendan Eich, who worked at Netscape Communications, created JavaScript in 1995. Brendan Eich's boss advised him to add Java Features because Java was popular at the time, and thus the problem began.

Java, Scheme, and Self-inspired JS.

  • Scheme: Functional programming language (does not have this, objects) inspired from Lisp.
  • Java: Object-oriented language
  • Self: Object-oriented programming language based on the concept of prototypes. Self. began as a dialect of Smalltalk.

Problem

let Dog = {
sound: 'woof',
talk: function ( ) {
console.log(this.sound) //[this depends on where it is called]
}
}

dog.talk( ); //woof
let talkFunction = Dog.talk
talkFunction(); //undefined

let talkFunction = dog.talk
talkFunction(function does not have this) = dog.talk (method)

Solution

let boundFunction = talkFunction.bind(dog) [forcing this to be dog]
bindFunction( ) //'woof'

this -> context is important

Code splitting is the splitting of code into components or numerous bundles which can be loaded when there is a demand or in parallel. Click to explore about, Code-Splitting in ReactJs

What is the difference between Imperative and Declarative?

Functional programming is a declarative paradigm, meaning that the program logic is represented without explicitly stating the flow control.

Imperative programs spend lines of code detailing the particular actions used to get the desired outputs β€” flow control: how things are done.

Declarative programs abstract the flow control mechanism (the how) and spend lines of code explaining the data flow: What to do instead.

What are the goals, and why are they important?

Any time you write some code, that forces the person to execute it in their head. Its harder to understand, is harder to maintain, is harder to improve, is harder to fix.

Early Declarative at some time earlier Now this is declarative
ar = [1,1,1,1]

ar[0] +ar[1] +ar[2] +ar[3]
sum = 0
for(i=0; i< ar.length; i++){
sum += ar[i];
}
sum = 0;
ar.forEach(num => sum + num)

What is the difference between Procedures and Function?

The below highlighted are the differences between Procedures and Function?

Procedures

To perform a series of steps, a function can be invoked. A procedure is a name for the sequence, and procedural programming is the term for programming in this way.

The procedure can take (0-N) inputs, return (0-N) output, and be called multiple times.

Suppose it does not have a return keyword. Functions that don't have a return keyword are procedures. In JS, all functions minimally return the undefined value, undefined is also a proper output, but a relationship should be there between input and output.

Functions can only call functions. If they call procedure, they become procedure.

Functions

According to Set theory. A mathematical function is a relation between 2 sets, input set, and output set, and & its mapping between two sets. Every function is a single-valued collection of pairs. const toLowerCase = { β€œA”: β€œa”, β€œB”: β€œb”, ……}

Function Purity: There must be the same corresponding output for a given input. You can even plot functions.

f(x) = 2x^2 + 3 function f(x) { // if you put x coordinate you get a y coordinate out
return 2 * Math.pow(x,2) + 3;
}
Even if you don't love math. But you trust math 1 + 1 = 2
X = [ β€˜a’, β€˜b’, β€˜c’]
Y = a(x)

What will be the value of x at the end?

Let’s call two many functions
Y = c(a(x) + b(x) + d(x)*e(x) - 4*(q(x) -f(x))
X -> is still the same. You don't need to look through 25 pages of code.
Math functions do not change over time(Monday or Tuesday..)
A core part of Angular and one of its most significant features. Click to explore about, Angular Dependency Injection

How does ES6 uplift JavaScript in functional programming?

ES6 uplift JS in functional programming is explained below:

Alonzo Church: (professor of Alan Turing)

The model computations in terms of pure functions(small units of expression called lambda expressions or anonymous functions)
ES6
  • Lambda expressions(anonymous functions)
const identity = x => x;
  • Rest Operator
const array = (...elements) => {
return elements;
}
array(1,2,3); //1,2,3
  • Spread Operator
const numbers = [1, 3, 5, 7];
function addNumbers(a, b, c, d) {
return a + b + c + d;
}
console.log(addNumbers(...numbers));
  • Destructuring
const favSportsPlayers = ["Virat Kholi", "Ronaldo", "Messi"];
const [indiaTeamCaptain, ...footballPlayers] = favSportsPlayers
indiaTeamCaptain === "Virat Kholi"
footballPlayers[0] === β€œRonaldo”
footballPlayers[1] === "Messi"

const head = ([x]) => x //const head=([x, ...rest]) => {return {x, rest}; }
head([1,2,3]) === 1
  • Immutable Objects create new obj using Object.assign
Object.assign(
{ },
{ hello: 'Ankit' },
{ hi: 'Xenonstack' }
);

Conclusion

Still thinking about why you should use functional programming. Functional Programming helps to achieve the Reliability, Portable, Reusable, Testable, Composable, and Properties/ Contracts.