Programming Paradigms
Functional Programming (FP) is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. In FP, programs are constructed by applying and composing functions.
The core idea of FP is to minimize or eliminate side effects. A side effect is any interaction a function has with the outside world that is not part of its return value. This includes modifying a global variable, writing to a file or database, or printing to the console.
Core Idea: Build programs from a set of "pure", stateless functions. The output of a function should depend only on its inputs, not on any external state.
Analogy: A perfect vending machine.
Languages: Haskell is a purely functional language. Many modern languages are multi-paradigm and have strong support for a functional style, including JavaScript, Python, C#, and Java (since version 8).
This is the cornerstone of FP. A pure function is a function that has two key properties:
// PURE function
// It's deterministic and has no side effects.
function add(a, b) {
return a + b;
}
// IMPURE function
let total = 0; // External state
function addToTotal(value) {
// It has a side effect: it modifies the 'total' variable.
// It's not deterministic: calling it twice with the same input produces a different result for 'total'.
total += value;
return total;
}
Why are pure functions so important?
Immutability means that once a data structure is created, it can never be changed. If you want to modify it, you must create a new data structure with the updated values.
This is the opposite of an "in-place" modification.
// MUTABLE approach (in-place modification)
const user = { name: "Alice", age: 30 };
function celebrateBirthday(person) {
person.age += 1; // This modifies the original object - a side effect!
return person;
}
celebrateBirthday(user); // user is now { name: "Alice", age: 31 }
// IMMUTABLE approach
const user2 = { name: "Bob", age: 25 };
function celebrateBirthdayImmutable(person) {
// Create a new object with the updated property.
return { ...person, age: person.age + 1 };
}
const olderBob = celebrateBirthdayImmutable(user2);
// user2 is still { name: "Bob", age: 25 }
// olderBob is { name: "Bob", age: 26 }
# Python lists are mutable
user_data = ["Alice", 30]
def celebrate_birthday(data):
data[1] += 1 # Modifies the original list
celebrate_birthday(user_data) # user_data is now ["Alice", 31]
# Python tuples are immutable
user_data_tuple = ("Bob", 25)
# user_data_tuple[1] += 1 # This would raise a TypeError
# You must create a new tuple
new_tuple = (user_data_tuple[0], user_data_tuple[1] + 1)
In FP, functions are "first-class citizens." This means they can be treated like any other variable:
A higher-order function is a function that either takes another function as an argument, returns a function, or both. These are the workhorses of functional programming.
Common examples include map, filter, and reduce.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
// 'map' is a higher-order function in Java Streams
Function<Integer, Integer> doubleFunction = x -> x * 2;
List<Integer> doubledNumbers = numbers.stream()
.map(doubleFunction)
.collect(Collectors.toList()); // [2, 4, 6, 8]
// 'filter' is also a higher-order function
Function<Integer, Boolean> isEvenFunction = x -> x % 2 == 0;
List<Integer> evenNumbers = numbers.stream()
.filter(isEvenFunction)
.collect(Collectors.toList()); // [2, 4]
// 'reduce' is a higher-order function
Function<Integer, Integer> sumFunction = (acc, x) -> acc + x;
int total = numbers.stream()
.reduce(0, sumFunction); // 10
// 'map' is a higher-order function. It takes a function as an argument.
const numbers = [1, 2, 3, 4];
const double = (x) => x * 2;
const doubledNumbers = numbers.map(double); // [2, 4, 6, 8]
// 'filter' is a higher-order function.
const isEven = (x) => x % 2 === 0;
const evenNumbers = numbers.filter(isEven); // [2, 4]
// 'reduce' is a higher-order function.
const sum = (acc, x) => acc + x;
const total = numbers.reduce(sum, 0); // 10
# Python has the same concepts
numbers = [1, 2, 3, 4]
def double(x): return x * 2
doubled_numbers = list(map(double, numbers)) # [2, 4, 6, 8]
def is_even(x): return x % 2 == 0
even_numbers = list(filter(is_even, numbers)) # [2, 4]
from functools import reduce
def add(acc, x): return acc + x
total = reduce(add, numbers) # 10
Function composition is the process of combining two or more functions to produce a new function. The output of one function becomes the input of the next.
f(g(x))
This allows you to build complex operations by chaining together simple, reusable pure functions.
const toUpperCase = (str) => str.toUpperCase();
const exclaim = (str) => `${str}!`;
const shout = (str) => exclaim(toUpperCase(str));
console.log(shout("hello")); // "HELLO!"
// Using a compose utility for more complex chains
const compose = (f, g) => (x) => f(g(x));
const shoutWithCompose = compose(exclaim, toUpperCase);
console.log(shoutWithCompose("hello again")); // "HELLO AGAIN!"
map, filter, reduce). They are essential for abstracting control flow.