Tuesday, 30 January 2024

Think Differently, Code Differently: Demystifying Functional Programming

Functional programming is a different way of thinking about and writing code compared to structural, object-oriented programming. Here are some key principles of functional programming. I am using a functional programming language ‘Haskell’ to demonstrate the examples.

 

1. Functions are first class citizen

Functions are the basic building blocks in functional programming, unlike object oriented programming languages; a function is not enclosed inside a class. A function can be passed as an argument to other function, a function can return result as a function, You can assign a function to a variable etc., In summary, you can use a function like variable.

 

Example

let sum x y = (x + y)

 

Above statement define a function named sum, which takes two number arguments and return the sum of two numbers. In Haskell, let key word is used to define variables, functions in Haskell interpreter.

 

2. Pure functional programming is side effect free

A Pure functional programming language has no side effects. A function is said to have side effect, if the result is not completely depend on its arguments. For example, a particular function might modify a global variable or static variable, modify one of its arguments, raise an exception, write data to a display or file, read data, or call other side-effecting functions. In the presence of side effects, a program's behaviour may depend on history.

 

For example, observe following code.

 

public class ProcessData {
 private static int x = 10;

 public static int f(int a) {
  x = x + a;
  return x;
 }

 public static int g(int a) {
  x = x * a;
  return x;
 }
}

 

Result of functions f, g is depend on the global variable x, and result is also depend on the order of execution of functions f, g.

 

If you call function f(5) first followed by g(5), then f(5) return 15, g(5) return 75. If you call function g(5) first followed by f(5), then f(5) return 55, g(5) return 50.

 

A side effect free function always returns same value for same input, i.e., it doesn’t depend on any global variable, external data, and order of executions.

 

Note

Side effects (Such as writing data to external systems, read data from networks etc.,) are still possible in Haskell, but Haskell is designed like that, it separates the pure code from impure(side-affect) code.

 

3. Functional programming is lazy

In functional programming, expressions are not evaluated until their results are actually needed.

Prelude> take 5 [1..]
[1,2,3,4,5]

 

[1..] represent infinite list, take function takes a number ‘n’ and list as arguments and return first ‘n’ number of elements.

 

4. Immutable data

In functional programming, data is immutable. Once created, a data structure cannot be altered. Any modifications to a data structure result in a new data structure. This leads to safer and more predictable code, especially in concurrent and parallel programming

 

5. Function composition is every where

A function output can be passed as input to other function. Combining functions by passing output of one function as input to other function is called composition of functions.

 

For example,

Let g(x) = 2x, f(x) = x + 1

then

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

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

Prelude> let g x = 2 * x
Prelude> let f x = x + 1
Prelude> 
Prelude> f(g 10)
21
Prelude> g(f 10)
22

 

6. Advantages of Functional Programming:

 

a.   Reliable program: The use of immutable data and pure functions reduces the likelihood of bugs in the software.

b.   Better modularity and easier maintenance: The declarative nature and modular structure of the code make it simpler to comprehend, test, and troubleshoot.

c.    Effecient concurrent execution: The inherent parallelism of pure functions makes them ideal for use in environments with multiple cores and distributed systems.

 

Common functional programming languages include Haskell, Lisp, Erlang, Scala, and Clojure, though many modern languages like JavaScript, Python, and Ruby support functional programming concepts to varying degrees.

 

7. Quick sort algorithm in Haskell

Following snippet implements quick sort algorithm. By looking into the code, you can easily guess what is happening here.

qsort [] = []
qsort (x:xs) = (qsort left) ++ [x] ++ (qsort right)
               where
                   left = filter (<= x) xs
                   right = filter (> x) xs

Function Definition:

The program defines a function named qsort. In Haskell, functions are defined by specifying the function name, followed by its parameters. Here, qsort takes one parameter, which is a list.

 

Pattern Matching:

Haskell uses pattern matching to decide what action to take based on the input. In this case, qsort has two definitions:

 

qsort [] = []: This is the base case. It states that if qsort is called with an empty list ([]), it should return an empty list. This is an example of a base case in a recursive function.

 

qsort (x:xs): This is the recursive case. It's saying "if qsort is called with a non-empty list, split the list into a head (x) and a tail (xs). x is the first element of the list, and xs is the rest of the list.

 

Recursion:

qsort is defined in terms of itself, which is a common pattern in functional programming known as recursion. The sorted list is obtained by recursively sorting two smaller lists and then concatenating them together with the pivot element (x).

 

The where Clause:

This is a way to define local variables in Haskell. In this instance, left and right are two lists, defined as follows:

 

a.   left = filter (<= x) xs: This creates a list of all elements in xs that are less than or equal to x. It uses the filter function which, as its name suggests, filters a list based on a given condition.

b.   right = filter (> x) xs: Similarly, this list contains all elements in xs that are greater than x.

 

List Concatenation:

The ++ operator is used to concatenate lists. So, (qsort left) ++ [x] ++ (qsort right) means: take the sorted left list, concatenate it with a list containing only x, and then concatenate the result with the sorted right list.

 

Functional Concepts used in this program:

a.   Immutability: The list being sorted is never modified; instead, new lists are created during the sorting process.

b.   Pure Functions: qsort is a pure function. Given the same input list, it always produces the same output without causing any side effects.

c.    Recursion: Rather than using loops, qsort achieves repetition through recursive function calls.

d.   Understanding this program gives insight into functional programming's emphasis on using functions, recursion, and immutable data to create clear and concise programs.

 

In summary, although functional programming provides numerous advantages, it is not universally suitable for all scenarios. Imperative programming continues to dominate various fields, and adopting a functional programming approach needs a different mindset. Nonetheless, gaining knowledge of functional programming principles can be advantageous for any programmer, enhancing their ability to write clear code and develop robust reasoning skills.



                                                           System Design Questions

No comments:

Post a Comment