Search This Blog

2024/04/04

Javascript:Functional Programming

What is functional programming?
Functional programming is a declarative programming paradigm
style where one applies pure functions in sequence to solve
complex problems. Functions take an input value and produce
an output value without being affected by the program. Functional
programming mainly focuses on what to solve and uses expressions
instead of statements. Functional programming excels mostly at
mathematical functions where the values don’t have any correlation
and doesn’t make use of concepts like shared state and mutable data
used in object-oriented programming.

Functional Programming Concepts:

First-class functions
First-class functions in functional programming are treated as data type
variables and can be used like any other variables. These first-class
variables can be passed to functions as parameters, or stored in data
structures.

Recursion
Unlike object-oriented programming, functional programming doesn’t make
use of “while” or ”for” loops or “if-else” statements. Functional programs
avoid constructions that create different outputs on every execution.
Instead, recursive functions call themselves repeatedly until they reach
the desired state or solution known as the base case.

Lets consider a function that returns true when any of its argument is
true otherwise false

Code:
// Function that uses for loop.
function onlyOneWithLoop(value1, value2, value3) {
var array = [value1, value2, value3];
var count = 0;
for (var i = 0; i < array.length; i++) {
if (array[i]) {
count++;
}
}

return count === 1;
}

console.log(onlyOneWithLoop(true, false, false));

Lets rewrite this function without using loop

Code:
function onlyOneWithRecursion(value1, value2, value3, count, i) {
var array = [value1, value2, value3];

if (i === array.length) return count === 1;
if (array[i]) count++;

return onlyOneWithRecursion(value1, value2, value3, count, ++i);
}

console.log(onlyOneWithRecursion(true, false, false, 0, 0));

Immutability
In functional programming, we can’t modify a variable after being created.
The reason for this is that we would want to maintain the program's state
throughout the runtime of the program. It is best practice to program each
function to produce the same result irrespective of the program's state.
This means that when we create a variable and assign a value, we can run
the program with ease fully knowing that the value of the variables will
remain constant and can never change.

Pure functions form the foundation of functional programming and have two
major properties:

1) They produce the same output if the given input is the same
2) They have no side effects

Pure functions work well with immutable values as they describe how inputs
relate to outputs in declarative programs. Because pure functions are
independent this means that they are reusable, easy to organize, and debug,
making programs flexibly and adaptable to changes. Another advantage of
using pure functions is memoization. This is when we cache and reuse the
results after computing the outputs from the given inputs.

High order functions
A function that accepts other functions as parameters or returns functions
as outputs is called a high order function. This process applies a function
to its parameters at each iteration while returning a new function that
accepts the next parameter.

Strict versus non-strict evaluation:
Functional languages can be categorized by whether they use strict (eager) or
non-strict (lazy) evaluation, concepts that refer to how function
arguments are processed when an expression is being evaluated.

Consider code below
Code:
console.log([2+1, 3*2, 1/0, 5-4].length)
Output:
4

The expression above fails under strict evaluation because of the
division by zero in the third element of the list. Under lazy evaluation,
the length function returns the value 4. since evaluating it does not
attempt to evaluate the terms making up the list. In brief, strict
evaluation always fully evaluates function arguments before invoking the
function. Lazy evaluation does not evaluate function arguments unless
their values are required to evaluate the function call itself.Lazy
evaluation is used by default in several pure functional languages.

Type systems:
A type system is a set of rules and principles that define how types are
organized, classified, and manipulated in a language. Different type
systems have different properties and trade-offs, such as expressiveness,
safety, and performance.Functional programming languages tend to have rich
and powerful type systems that support features such as algebraic data
types, generics, polymorphism,and higher-kinded types.

Another feature of functional programming languages is that they often
use type classes, which are a way of defining and implementing generic
behaviors for different types.you can implement type class for different
types, such as integers or strings.

JavaScript don't have type classes like in Haskell, but we can achieve
similar functionality using interfaces or generic functions that work
with any type that implements specific behaviors.

e.g.
Code:
// Define a higher-order function for generic sorting
function mySort(arr, compareFn) {
return arr.slice().sort(compareFn);
}

// Define a compare function for numbers
function compareNumbers(a, b) {
return a - b;
}

// Define a compare function for strings (lexicographical order)
function compareStrings(a, b) {
return a.localeCompare(b);
}

// Usage example
let numbers = [5, 2, 7, 1, 9];
console.log("Original numbers array:");
console.log(numbers);
console.log("Sorted numbers array:");
console.log(mySort(numbers, compareNumbers));

let strings = ["banana", "apple", "cherry"];
console.log("Original strings array:");
console.log(strings);
console.log("Sorted strings array:");
console.log(mySort(strings, compareStrings));


Referential transparency:
Functional programs do not have assignment statements, that is, the value
of a variable in a functional program never changes once defined. This
eliminates any chances of side effects because any variable can be
replaced with its actual value at any point of execution. So, functional
programs are referentially transparent.

Consider assignment statement x=x * 10, this changes the value assigned
to the variable x.Let us say that the initial value of x was 1, then two
consecutive evaluations of the variable x yields 10 and 100 respectively.
Clearly, replacing x=x * 10 with either 10 or 100 gives a program a
different meaning, and so the expression is not referentially transparent.

Now, consider another function such as int plusone(int x) {return x+1;}
is transparent, as it does not implicitly change the input x and thus has
no such side effects. Functional programs exclusively use this type of
function and are therefore referentially transparent.
What are advantages of functional programming ?

Easy to debug:
Since pure functions produce the same output as the given input, this
means they aren’t any changes or any other hidden output produced.
Functional programming functions are immutable, this also means that
it’s easier to check for errors in code faster.

Lazy evaluation:
Functional programming adopts the lazy evaluation concept, whereby the
computations are only evaluated the moment they are needed. This gives
programs the ability to reuse results produced from previous computations.

Supports parallel programming:
Because functional programming uses immutable variables, creating
parallel programs is easy as they reduce the amount of change within
the program. Each function only has to deal with an input value and have
the guarantee that the program state will remain constant.

Easy to read:
Functions in functional programming are easy to read and understand.
Since functions are treated as values, immutable, and can be passed as
parameters, it is easier to understand the codebase and purpose.

Efficient:
Since functional programs don’t rely on any external sources or variables
to function, they are easily reusable across the program. This makes them
more efficient as there isn’t extra computation needed to source the
programs or run operations on runtime.

What are drawbacks of Functional Programming?

Terminology Problems:
Because of its mathematical roots, functional programming has a lot
of terminologies that may be difficult to explain to a layman. Terms
like “pure functions” can easily scare off people looking to learn
more about functional programming.

Recursion:
Although recursion is one of the best features in functional
programming, it is very expensive to use. Writing recursive functions
requires higher memory usage which can be costly.

Explore Further:
Terms:
graph reduction,tail recursion,lambda calculus,covariant type


No comments:

Post a Comment