Functional Programming
Pure functions, immutability, and composability
IT & Tech Reports | Class IM24A | 2026
1. What is Functional Programming?
Functional Programming (FP) is a programming paradigm that treats computation as the evaluation of
mathematical functions. It avoids changing state and mutable data. Code is built by composing small,
pure functions rather than sequences of statements that modify shared state.
2. Core Concepts
Concept Definition Example
Pure function Same input always produces same output;
add(2,3)
no side
always
effects
returns 5
Immutability Data cannot be changed after creation Create new objects instead of mutating
First-class fns Functions are values — pass, return, assign
callbacks, higher-order functions
Higher-order fns Functions that take or return other functions
map, filter, reduce
Referential transparency Expression can be replaced by its valueEnables memoisation and reasoning
Recursion Functions call themselves instead of loops
factorial(n) = n * factorial(n-1)
3. Pure Functions vs Side Effects
# IMPURE — modifies external state
total = 0
def add_to_total(x):
global total
total += x # side effect!
# PURE — no side effects, same output for same input
def add(a: int, b: int) -> int:
return a + b
# IMPURE — depends on external state (datetime)
def get_greeting():
if [Link]().hour < 12:
return "Good morning"
return "Good afternoon"
4. Map, Filter, Reduce
numbers = [1, 2, 3, 4, 5, 6]
# map — transform each element
doubled = list(map(lambda x: x * 2, numbers)) # [2,4,6,8,10,12]
# filter — keep elements matching predicate
evens = list(filter(lambda x: x % 2 == 0, numbers)) # [2,4,6]
# reduce — fold list into single value
from functools import reduce
total = reduce(lambda acc, x: acc + x, numbers, 0) # 21
# Pythonic equivalent using comprehensions
doubled = [x * 2 for x in numbers]
evens = [x for x in numbers if x % 2 == 0]
5. Function Composition & Currying
from functools import partial
# Composition: apply functions right-to-left
def compose(*fns):
def composed(x):
for fn in reversed(fns):
x = fn(x)
return x
return composed
double = lambda x: x * 2
inc = lambda x: x + 1
double_then_inc = compose(inc, double)
double_then_inc(3) # inc(double(3)) = 7
# Partial application (currying)
def power(base, exp): return base ** exp
square = partial(power, exp=2)
square(5) # 25
6. Immutability in Practice
# MUTABLE — dangerous shared state
user = {"name": "Ivan", "score": 0}
user["score"] += 10 # mutates in place
# IMMUTABLE — create new object
import copy
updated_user = {**user, "score": user["score"] + 10}
# Python: use tuples and frozensets for immutable collections
point = (47.4, 8.5) # immutable
allowed = frozenset(["admin", "editor"]) # immutable set
7. FP in JavaScript
// Pure function
const add = (a, b) => a + b;
// Immutability with spread
const user = { name: "Ivan", score: 0 };
const updated = { ...user, score: [Link] + 10 };
// Chaining higher-order functions
const result = [1,2,3,4,5]
.filter(x => x % 2 !== 0)
.map(x => x ** 2)
.reduce((acc, x) => acc + x, 0); // 1 + 9 + 25 = 35
8. When to Use FP
• Data transformation pipelines — map/filter/reduce chains are clear and testable
• Concurrent and parallel code — pure functions are inherently thread-safe
• Financial and scientific computing — immutability prevents subtle mutation bugs
• Event-driven systems — pure event handlers are easy to test and reason about
• Mix FP and OOP pragmatically — use pure functions for logic, classes for state management