Functional Programming: Pure Functions, Immutability & Composition
Functional programming treats computation as the evaluation of pure functions, favoring immutable data and avoiding shared mutable state and side effects. These examples use JavaScript, but the concepts apply across languages -- most mainstream languages support FP techniques even without being functional-first.
Pure Functions & Side Effects
// PURE: output depends only on inputs, no observable side effects
function add(a, b) {
return a + b;
}
add(2, 3); // always 5, forever, for these inputs
// IMPURE: reads external mutable state
let taxRate = 0.08;
function addTax(price) {
return price * (1 + taxRate); // depends on something outside its arguments
}
// IMPURE: non-deterministic (hidden dependency on Math.random)
function rollDice() {
return Math.floor(Math.random() * 6) + 1;
}
// PURE alternative: randomness becomes an explicit input (a seed),
// restoring determinism and referential transparency
function rollDiceWithSeed(seed) {
return (seed % 6) + 1;
}
// IMPURE: mutates its argument
function addItem(cart, item) {
cart.push(item); // caller's array is mutated -- a surprising side effect
return cart;
}
// PURE: returns a new array, leaves the original untouched
function addItemPure(cart, item) {
return [...cart, item];
}Immutability
const original = [1, 2, 3];
// map/filter never mutate -- they return NEW arrays. Unlike push/
// splice/sort, which DO mutate in place.
const doubled = original.map(x => x * 2);
console.log(original); // [1, 2, 3] -- unchanged
// Object spread for immutable updates
const user = { name: 'Alice', age: 30 };
const olderUser = { ...user, age: 31 }; // user itself is untouched
// Why it matters for concurrency: if data is never mutated after
// creation, there's nothing for concurrent readers to race over --
// every reader sees a value that can't change underneath them.Higher-Order Functions & Composition
// map/filter/reduce: declarative -- WHAT transformation, not HOW to loop
const users = [{ name: 'Alice', active: true }, { name: 'Bob', active: false }];
const activeNames = users
.filter(u => u.active)
.map(u => u.name);
const totalAge = [30, 25, 40].reduce((sum, age) => sum + age, 0);
// Function composition: output of one becomes input of the next
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);
const process = pipe(
(s) => s.trim(),
(s) => s.toLowerCase(),
(s) => s.replace(/\s+/g, '-'),
);
process(' Hello World '); // 'hello-world'
// Point-free style: composing functions without naming the data
// flowing through them
const double = x => x * 2;
const doubleAll = (arr) => arr.map(double); // 'arr' is the only named valueKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free