Track progress, take quizzes and save notes on this lesson.

Free forever · no card needed

Start free
Advanced

Functional Programming in Practice

4.12.2 Writing functional programs·4.12.3 Lists in functional programming

Aligned to the AQA 7517 specification

Level
Advanced
Reading time
5 min
Published
13 June 2026
Updated
1 July 2026
On this page
  1. 1.Higher-Order Functions
  2. 2.map
  3. 3.filter
  4. 4.fold (reduce)
  5. 5.Lists: Head, Tail, and Construction
  6. 6.Writing Functional Programs
  7. 7.Common Exam Mistakes

Key takeaways

  • A higher-order function either takes a function as an argument or returns a function as its result (or both); map, filter and fold are the standard examples.
  • map applies a function to every element of a list and returns a new list of the same length, while filter keeps only elements for which a predicate returns True, so its output may be shorter.
  • fold (reduce) repeatedly applies a function to an accumulator and each element to produce a single value; foldr processes right to left and foldl left to right, which matters for non-associative operations.
  • A list is defined recursively as either the empty list [] or a head prepended to a tail (head : tail), so [1, 2, 3, 4] is 1 : 2 : 3 : 4 : [].
  • The prepend operator : adds one element to a list and is O(1), whereas ++ concatenates two lists and is O(n); calling head or tail on [] is an error.

Higher-Order Functions

A higher-order function is a function that either:

  • Takes a function as an argument, or
  • Returns a function as its result (or both)

Higher-order functions are central to functional programming. They allow the separation of a pattern of computation from the specific operation being applied.

Examples:

-- apply takes a function and a value; applies the function
apply f x = f x

-- twice applies a function two times
twice f x = f (f x)
twice (+3) 5  -- evaluates to 11  (5+3=8, 8+3=11)

-- compose returns a new function (composition)
compose g f = \x -> g (f x)

The standard higher-order functions map, filter, and fold are the most commonly examined.

map

map f list applies a function f to every element of a list and returns a new list containing the results.

map :: (a -> b) -> [a] -> [b]

Type: takes a function from a to b, a list of a, returns a list of b.

Examples:

map (*2) [1, 2, 3, 4]       -- [2, 4, 6, 8]
map even [1, 2, 3, 4]       -- [False, True, False, True]
map length ["cat", "dog", "elephant"]  -- [3, 3, 8]
map (+10) []                -- []

The original list is not modified — map returns a new list. This is functional programming's immutability in action.

filter

filter pred list returns a new list containing only the elements of list for which the predicate function pred returns True.

filter :: (a -> Bool) -> [a] -> [a]

Examples:

filter even [1, 2, 3, 4, 5, 6]     -- [2, 4, 6]
filter (>10) [3, 15, 7, 22, 1]     -- [15, 22]
filter (/= 'a') "banana"            -- "bnn"
filter even []                      -- []

pred must be a function that takes one argument and returns Bool. Partial application is often used to create predicates: (>10) is \x -> x > 10.

fold (reduce)

fold (also called reduce) processes a list by repeatedly applying a function to an accumulator and each list element, ultimately producing a single value.

foldr :: (a -> b -> b) -> b -> [a] -> b
foldl :: (b -> a -> b) -> b -> [a] -> b

Parameters: function f, initial value (accumulator), list.

foldr (fold right) example — sum a list:

foldr (+) 0 [1, 2, 3, 4]
= 1 + (2 + (3 + (4 + 0)))
= 10

foldr example — build a list:

foldr (:) [] [1, 2, 3]   -- [1, 2, 3]  (reconstructs the list)

foldl example — product:

foldl (*) 1 [1, 2, 3, 4]
= ((((1 * 1) * 2) * 3) * 4)
= 24

fold generalises many common patterns: sum, product, maximum, count, string concatenation, and list construction.

Worth saving these ideas?

Turn what you've read into instant revision cards. Free to get started.

Make flashcards

Lists: Head, Tail, and Construction

In functional programming, a list is defined recursively as either:

  • The empty list: []
  • A head (first element) prepended to a tail (the rest of the list): head : tail
[1, 2, 3, 4]  is equivalent to  1 : 2 : 3 : 4 : []

Standard list operations:

OperationHaskellResult
Return head (first element)head [1, 2, 3]1
Return tail (all but first)tail [1, 2, 3][2, 3]
Test for empty listnull []True
Return lengthlength [1, 2, 3]3
Construct empty list[][]
Prepend item4 : [3, 5][4, 3, 5]
Append item[3, 5] ++ [7][3, 5, 7]

Recursive list processing pattern:

-- Manually reimplementing sum
mySum []     = 0
mySum (x:xs) = x + mySum xs

The pattern (x:xs) matches a non-empty list, binding x to the head and xs to the tail. This is how most recursive list functions are structured.

Writing Functional Programs

Worked example — double all even numbers in a list:

doubleEvens xs = map (*2) (filter even xs)

-- Or using composition:
doubleEvens = map (*2) . filter even

doubleEvens [1, 2, 3, 4, 5, 6]  -- [4, 8, 12]

Worked example — count elements satisfying a predicate:

countWhere pred xs = length (filter pred xs)

countWhere even [1, 2, 3, 4, 5]   -- 2
countWhere (>10) [5, 15, 3, 20]   -- 2

Worked example — sum of squares:

sumOfSquares xs = foldr (+) 0 (map (^2) xs)

sumOfSquares [1, 2, 3, 4]   -- 1 + 4 + 9 + 16 = 30

Common Exam Mistakes

1. Confusing map and filter

map transforms every element — the output list has the same length as the input. filter selects elements — the output list may be shorter. A question asking to "keep only even numbers" requires filter; a question asking to "double all numbers" requires map.

2. Getting fold direction wrong

foldr processes the list from right to left (last element first, accumulator on the right). foldl processes from left to right. For associative operations like + and *, both give the same result. For non-associative operations (e.g. subtraction, list construction), the direction matters.

3. Calling head or tail on an empty list

head [] and tail [] are errors in Haskell — undefined for the empty list. Correct recursive functions must handle the base case [] before applying head/tail.

4. Confusing the : and <ins> operators

: prepends a single element to a list: 4 : [3, 5] = [4, 3, 5]. </ins> concatenates two lists: [4] <ins> [3, 5] = [4, 3, 5]. Using </ins> with a single element on the left works but is less efficient; : is O(1), ++ is O(n).

Key terms

Higher-order function
A function that takes a function as an argument, returns a function as its result, or both.
map
A function that applies a given function to every element of a list and returns a new list of results.
filter
A function that returns a new list of only the elements for which a predicate function returns True.
fold (reduce)
A function that processes a list by repeatedly applying a function to an accumulator and each element, producing a single value.
Accumulator
The running value that fold combines with each list element and ultimately returns.
Head
The first element of a list.
Tail
The rest of a list after the head, that is all elements but the first.
Predicate
A function that takes one argument and returns Bool, used by filter to decide which elements to keep.
Partial application
Supplying some arguments to a function to create a more specific function, as in (>10) meaning \\x -> x > 10.

Frequently asked questions

map transforms every element, so the output list has the same length as the input. filter selects elements using a predicate that returns Bool, so the output may be shorter. Use filter to keep only certain elements and map to transform all of them.

foldr processes a list from right to left with the accumulator on the right, while foldl processes from left to right. For associative operations like + and * both give the same result, but for non-associative ones like subtraction or list construction the direction matters.

head [] and tail [] are undefined in Haskell, so they cause errors. Recursive list functions must handle the base case [] before applying head or tail, since the empty list has no first element or remainder.

Generate revision on any topic you study

Type any topic you're studying and Aicademy generates a complete lesson, quiz, and flashcard set, personalised to your level.

Lessons on anything

Structured, level-matched lessons on any topic you study

Practice quizzes

Find out what you actually know before the exam does

Flashcard sets

Lock in key concepts with instant revision cards

Ask Aica

Stuck on something? Get a clear explanation, any time

Prev

Functional Programming Paradigm

Next

Systematic Software Development

Related lessons

Top students don’t revise more. They revise what counts.

Start revising free

Free to start. No card needed.