Sunday, 29 August 2021

Functional Programming Using JavaScript

 Programming languages are classified in number of ways. One popular method for classfying is Programming paradigm

Let's look at couple of paradigm that are relevant to current topic. 

Imperative is where  programmer instruct a machine how to change its state. Procedural and object oriented programming are derived from Imperative Programming. 

Declarative is where a programmer only defines properties of results leaving how to compute it. Functional programming falls under this category. The desired result is declared as the value of series of function applications.

Fundamental difference between procedural, object-oriented, and functional programming.

Procedural Programming

It can be represented as assembly lines. 

"Raw Input → Step 1 → Step 2 → … → Step n → Final Product. 

  • Raw input is changed (mutated) at every step. 

  • Each step is depend upon previous step. 

  • There is no meaning of an individual step in isolation. 

  • We get only one specific product. If we need a slightly different change in product, then we need new assembly line. 

In terms of programming, the global mutable state (raw material is changing at every step) creates interdependencies. 

Object-Oriented Programming

Same as procedural but with some modularisation. The global state is broken down into objects a part of instruction can change only a part of state. Albeit, interdependencies still exist.

Functional Programming

It takes completely different approach. Programs are formed by appying and composing functions. A programmer tries to bind everything into purely mathematical function style. Using pure function instead of procedures avoids mutable state. The main focus is on what to solve in contrast to how to solve in imperative programming.

// Imperative
const list = [1, 2, 3, 4, 5];
const item = list[list.length - 1];
 
 
// Declarative
const list = [1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 15, 16, 18, 20];
const item = getLastItem(list);

Basic Concepts in Functional Programming : 
 
A programming language is said to have first-class functions when a function in that language is treated like any other variable.
 
A function can be : 
  • assigned to a variable
  • passed as an argument
  • returned by another function
// Assign a function to a variable
const foo = function() {
   console.log("foobar");
}
foo(); // Invokve using variable


// Pass a function as an argument
function sayHello() {
   return "Hello, ";
}
function greeting(helloMessage, name) {
  console.log(helloMessage() + name);
}
greeting(sayHello, "JavaScript!"); // Pass `sayHello` as an argument to `greeting` function


// Return a function
function sayHello() {
   return function() {
      console.log("Hello!");
   }
}
 
 

Higher-Order Function

Takes a function as an argument or returns a function or both.

 
// Takes function as an argument - map
const numbers = [1, 2, 3];
const doubledNumbers = numbers.map(number => number * 2); // [2, 4, 6]

// Returns a function
function sayHello() {
   return function() {
      console.log("Hello!");
   }
}
 
 

Immutability : 

Immutable means unchangeable. Once array/object is defined, it can't be modified. To change properties of object or change element of an array, one should create a new copy of an array or an object with a changed value.

 
var myCar = {
    make: 'Ford',
    model: 'Mustang',
    year: 1969
};
myCar.model = 'Mercedes';

myCar.year= 1999;

// Instead should be achieved as -

const myCar = {
    make: 'Ford',
    model: 'Mustang',
    year: 1969
};

const updatedCar = {
    ...myCar ,
    model: 'BMW',
};

const latestYear = {
    ...updatedCar ,
    year: 2021,
};
 
 
// Get all evens

const numbers = [2, 4, 5, 6, 8, 10];
numbers.splice(2, 1);
console.log(numbers); // [2, 4, 6, 8, 10]

// Instead should be achieved as -

const numbers = [2, 4, 5, 6, 8, 10];
const evens = [...numbers.slice(0, 2), ...numbers.slice(3)];
console.log(evens); // [2, 4, 6, 8, 10]
 
 

Pure Function

 A pure function is a function that given the same input will always return the same output and does not have any observable side effects.

 
Side effects include - 
  • changing a file system
  • inserting a record in a DB
  • querying DOM
  • mutations

 

// Impure
const list = [1,2,3,4,5];

list.splice(0,3); // [1,2,3]

list.splice(0,3); // [4,5]

list.splice(0,3); // []

// Pure
const list = [1,2,3,4,5];

list.slice(0,3); // [1,2,3]

list.slice(0,3); // [1,2,3]

list.slice(0,3); // [1,2,3]
 
 
 
const list = [1,2,3,4,5];

// impure
const addToList = (list, number) => {
  list.push(number);
  return list;
}

// pure
const addToList = (list, number) => {
  const newList = [...list];
  newList.push(number);
  return newList;
}
 

Currying

Currying is where you can call a function with fewer arguments than it expects. It then returns a function that takes the remaining arguments.

 
const discount = (price, percent) => (price * percent);
discount(100, 0.1); // 10

// Currying

const discount = percent => price => price * percent;

const flat10Percent = discount(0.1);
const flat50Percent = discount(0.5);
const newYearDiscount = discount(0.7);

flat10Percent(100); // 10
flat50Percent(100); // 50
newYearDiscount(100); // 70
 
 
function sum(a, b) {
  return a + b;
}

// Actual    : sum(1, 2);
// Expected  : sum(1)(2);

function curry(f) {
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}
let curriedSum = curry(sum);
curriedSum(1)(2); // 3
 

Composition

Composition simply is to compose 2 functions to create a new function.

 

 
f(x) = x * 2
g(y) = y + 1

g.f = g(f(x))

composition:    g(f(x)), for x = 2; Result = 5


f: x -> y
g:      y -> z
h: x    ->   z
__________________________
For x = 2:

f: 2 -> 4
g:      4 -> 5
h: 2    ->   5 


const f = x => x * 2;
const g = y => y + 1;

const compose = (g, f) => x => g(f(x));
const h = compose(g, f);
h(2); // 5

Pointfree

Pointfree simply means we don’t explicitly specify what data is being passed to a function.

f(x) = g(x)

// Point free
f = g

-------------------------------------

const numbers = [1, 2, 3, 4, 5];
const doubles = numbers.map(x => x * 2);

// Making it pointfree

const double = x => x * 2
const numbers = [1, 2, 3, 4, 5]
const doubles = numbers.map(double); // Point free
 
Instead of grasping all difficult principles of functional programming, one could start small by breaking large functions into smaller reusable ones and then composing them together.
 
Hope the tiny gists help you understand the concepts. 
 

Checkout very powerful and helpful funnel & web page builder which automates Traffic, Leads, Commissions and Sales
 
Thanks for reading :) 

1 comment: