Skip to content

You are viewing a free preview of this lesson.

Subscribe to unlock all 10 lessons in this course and every other course on LearningBro.

What is Functional Programming?

What is Functional Programming?

Functional programming (FP) is a programming paradigm where programs are constructed by applying and composing functions. Unlike imperative programming, which describes how to do something step by step with mutable state, functional programming focuses on what to compute by evaluating mathematical functions without side effects.


Programming Paradigms

A paradigm is a style or approach to programming. The three main paradigms you need to know for A-Level are:

Paradigm Description Examples
Imperative / Procedural Step-by-step instructions that change program state C, Pascal, Python (procedural style)
Object-Oriented Models real-world entities as objects with attributes and methods Java, C#, Python (OOP style)
Functional Computation through function application with no mutable state Haskell, Lisp, Erlang, F#

Many modern languages are multi-paradigm — Python, JavaScript, and Scala support both imperative and functional styles.


Key Characteristics of Functional Programming

1. Functions as the Primary Building Block

In FP, functions are the fundamental unit of computation. Programs are built by defining functions and combining them, rather than by writing sequences of instructions.

2. No Side Effects

A side effect is any observable change outside the function — modifying a global variable, writing to a file, printing to the screen, or changing the input data. In pure functional programming, functions have no side effects.

3. Immutability

Data is immutable — once a value is assigned, it cannot be changed. Instead of modifying existing data, you create new data structures with the desired changes.

4. Declarative Style

FP uses a declarative style: you describe what result you want, not how to compute it step by step.

Imperative (how):

# Sum the squares of even numbers from 1 to 10
total = 0
for i in range(1, 11):
    if i % 2 == 0:
        total += i * i

Functional (what):

# Same computation, declarative style
total = sum(x*x for x in range(1, 11) if x % 2 == 0)

Functional vs Imperative: A Comparison

Feature Imperative Functional
State Mutable — variables change over time Immutable — values do not change
Control flow Loops (for, while), conditionals Recursion, function composition
Side effects Common (print, file I/O, mutations) Avoided — pure functions have none
Primary abstraction Procedures / methods Functions
How vs What Describes how to compute Describes what to compute
Data Modified in place New data created from old data

Why Study Functional Programming?

  1. Easier to reason about. Since functions always produce the same output for the same input (referential transparency), you can understand and predict behaviour more easily.

  2. Easier to test. Pure functions with no side effects are straightforward to test — provide an input, check the output.

  3. Better for parallelism. With no shared mutable state, functional programs can be safely run across multiple processors without race conditions.

  4. Mathematical foundation. FP is rooted in lambda calculus, a formal system developed by Alonzo Church in the 1930s.

  5. Growing industry adoption. Functional concepts are increasingly used in mainstream languages. Map, filter, and reduce are now standard in Python, JavaScript, Java, and C#.


Lambda Calculus — The Foundation

Functional programming is based on lambda calculus (the lambda calculus), a mathematical model of computation.

In lambda calculus, everything is expressed as:

  • Variables: x, y, z
  • Abstractions (functions): \ x -> x + 1 (a function that takes x and returns x + 1)
  • Applications: (\x -> x + 1) 5 evaluates to 6

Haskell uses this notation directly:

-- A lambda function that doubles a number
double = \x -> x * 2

-- Applying it
double 5    -- Result: 10

Domain and Co-domain

In mathematics, a function maps values from a domain (set of valid inputs) to a co-domain (set of possible outputs).

Example: The function f(x) = x^2 where x is a positive integer:

  • Domain: {1, 2, 3, 4, ...} (positive integers)
  • Co-domain: {1, 4, 9, 16, ...} (perfect squares)

In Haskell, types serve as domains and co-domains:

square :: Int -> Int
square x = x * x

This declares that square takes an Int (domain) and returns an Int (co-domain).


Worked Example

Scenario: Compare an imperative approach and a functional approach to finding all even numbers in a list and doubling them.

Imperative (Python):

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = []
for n in numbers:
    if n % 2 == 0:
        result.append(n * 2)
# result = [4, 8, 12, 16, 20]

Functional (Python):

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = list(map(lambda n: n * 2, filter(lambda n: n % 2 == 0, numbers)))
# result = [4, 8, 12, 16, 20]

Functional (Haskell):

result = map (*2) (filter even [1..10])
-- result = [4, 8, 12, 16, 20]

Notice how the functional versions describe what to do (filter even numbers, then double them) rather than how (loop through, check, append).


Exam Tips

  • Be prepared to compare imperative and functional paradigms — examiners often ask for advantages and disadvantages of each.
  • Know the key characteristics: immutability, no side effects, functions as first-class objects, declarative style.
  • Understand that lambda calculus is the mathematical foundation of functional programming.
  • Be able to explain domain and co-domain in the context of function types.
  • Remember that functional programming is not "better" or "worse" than imperative — each has strengths for different problems.