Revision notes for AQA A Level Computer Science Functional programming paradigm. Open the guide for explanations and worked examples. Written against the AQA A Level Computer Science specification, so the content matches what's examinable rather than general Computer Science background.

Functional programming paradigm

What you'll learn

  • How to read a function type such as f:ABf: A \rightarrow Bf:AB.
  • Why functions can be treated as first-class objects.
  • What happens when a function is applied to one or more arguments.
  • How partial application and function composition build new functions from existing ones.

Big picture: what is functional programming?

A programming paradigm is a style of programming: a set of ideas about how programs should be structured. In the functional programming paradigm, computation is mainly described by evaluating functions and combining functions.

This topic is mostly about the notation AQA expects you to recognise and use. You do not need to learn a particular functional language here; focus on the mathematical ideas behind functions.


4.12.1.1 Function type

Definition

Function type

A function fff has a type written f:ABf: A \rightarrow Bf:AB. This means the function takes an input from set AAA and returns an output from set BBB. The type itself is ABA \rightarrow BAB.

The set AAA is the argument type. It is also called the domain: the set from which input values are chosen.

The set BBB is the result type. It is also called the co-domain: the set from which output values are chosen.

A data type is a category of values, such as integer, character, Boolean or string. The domain and co-domain are always subsets of objects in some data type. For example, the set of lowercase letters is a subset of character values, and the set {0,1,2,,25}\{0,1,2,\dots,25\}{0,1,2,,25} is a subset of integer values.

A function does not have to use every value in its co-domain. It only needs to return values that belong to the co-domain.

The diagram shows a function from a domain to a co-domain, and also previews how two functions can be composed later in this topic.

Diagram showing domain, co-domain, unused co-domain values, and function composition

Key Idea

Domain versus co-domain

The domain is where inputs come from. The co-domain is where outputs are allowed to come from. Not every co-domain value must actually be produced.

For example, suppose:

f:{a,b,c,,z}{0,1,2,,25}f: \{a,b,c,\dots,z\} \rightarrow \{0,1,2,\dots,25\}f:{a,b,c,,z}{0,1,2,,25}

with the rule that a0a \mapsto 0a0, b1b \mapsto 1b1, and so on. Here the input values are letters, and the output values are integers from 0 to 25.

Example

Finding a function type

A function lengthOfWord takes one lowercase word and returns the number of characters in it. Assume the longest allowed word has 20 characters.

  1. Choose the domain by identifying the possible inputs: the input is one lowercase word, so the domain is a set of lowercase strings.
  2. Choose the co-domain by identifying the allowed outputs: the output is a whole number from 0 to 20, so the co-domain is {0,1,2,,20}\{0,1,2,\dots,20\}{0,1,2,,20}.
  3. Write the function type using arrow notation: lengthOfWord:lowercaseString{0,1,2,,20}\text{lengthOfWord}: \text{lowercaseString} \rightarrow \{0,1,2,\dots,20\}lengthOfWord:lowercaseString{0,1,2,,20}.
Common Mistake

Confusing co-domain with actual outputs

Do not assume the co-domain is exactly the set of values that will be produced. It is the set of values that may be used as outputs.


4.12.1.2 First-class object

Definition

First-class object

A first-class object is a value that may appear in expressions, be assigned to a variable, be passed as an argument, and be returned from a function call.

In many languages, integers, floating-point values, characters and strings are first-class objects. In functional programming languages, functions are also first-class objects.

Some imperative programming languages also support first-class functions. An imperative programming language is one where programs are mainly written as sequences of commands that update state. If such a language supports first-class functions, a function can be handled like other values.

This means a function can be:

  • stored in a variable;
  • passed into another function;
  • returned as the result of a function call;
  • used in an expression.

A function that takes another function as an argument, or returns a function, is often called a higher-order function.

Example

Passing a function as an argument

Suppose double is a function where double(n)=n×2\text{double}(n) = n \times 2double(n)=n×2, and applyTwice is defined as applyTwice(functionValue,x)=functionValue(functionValue(x))\text{applyTwice}(functionValue, x) = functionValue(functionValue(x))applyTwice(functionValue,x)=functionValue(functionValue(x)).

  1. Pass the function double as the first argument and 5 as the second argument: applyTwice(double,5)\text{applyTwice}(\text{double}, 5)applyTwice(double,5).
  2. Apply the inner function call first: double(5)=10\text{double}(5) = 10double(5)=10.
  3. Apply the function again to the result: double(10)=20\text{double}(10) = 20double(10)=20.
  4. Therefore, treating double as a first-class object allows applyTwice to return 20.
Tip

Spotting first-class functions

If a function is being passed around like data, stored in a variable, or returned by another function, it is being treated as a first-class object.


4.12.1.3 Function application

Definition

Function application

Function application means giving particular argument values to a function.

For example, add(3,4)\text{add}(3,4)add(3,4) is the application of the function add to the integer arguments 3 and 4.

A two-argument function can be described using the Cartesian product. The Cartesian product of two sets is the set of all ordered pairs formed by taking one value from each set.

So the type of add can be written as:

add:integer×integerinteger\text{add}: \text{integer} \times \text{integer} \rightarrow \text{integer}add:integer×integerinteger

Although we usually say add takes two arguments, formally this version takes one argument that is a pair, such as (3, 4).

Example

Applying a function to a pair

Let add:integer×integerinteger\text{add}: \text{integer} \times \text{integer} \rightarrow \text{integer}add:integer×integerinteger, where add(x,y)=x+y\text{add}(x,y) = x + yadd(x,y)=x+y. Find add(7,9)\text{add}(7,9)add(7,9).

  1. Treat the input as one ordered pair: (7, 9) belongs to integer×integer\text{integer} \times \text{integer}integer×integer.
  2. Substitute the pair values into the rule: add(7,9)=7+9\text{add}(7,9) = 7 + 9add(7,9)=7+9.
  3. Evaluate the result: 7+9=167 + 9 = 167+9=16, so the output is an integer, as required by the co-domain.

4.12.1.4 Partial function application

Definition

Partial function application

Partial function application means applying a function to fewer arguments than it ultimately needs, producing a new function that expects the remaining argument or arguments.

This idea relies on functions being first-class objects, because the result of partial application is itself a function.

One-argument functions

A one-argument function has type:

f:ABf: A \rightarrow Bf:AB

If you apply its single argument, the result has type BBB. There are no remaining arguments, so there is no useful partial application left to do.

Two-argument functions

A two-argument function can be viewed like this:

add:integer(integerinteger)\text{add}: \text{integer} \rightarrow (\text{integer} \rightarrow \text{integer})add:integer(integerinteger)

This means add takes one integer and returns a function. That returned function takes another integer and returns an integer.

The brackets may be dropped:

add:integerintegerinteger\text{add}: \text{integer} \rightarrow \text{integer} \rightarrow \text{integer}add:integerintegerinteger

So add 4\text{add}\ 4add 4 returns a new function that adds 4 to whatever integer it is later given.

Three-argument functions

A three-argument function can be viewed as:

h:ABCDh: A \rightarrow B \rightarrow C \rightarrow Dh:ABCD

This means:

h:A(B(CD))h: A \rightarrow (B \rightarrow (C \rightarrow D))h:A(B(CD))

So:

  • applying the first argument gives a function of type BCDB \rightarrow C \rightarrow DBCD;
  • applying the first two arguments gives a function of type CDC \rightarrow DCD;
  • applying all three arguments gives a final value of type DDD.
Tip

Arrow notation is right-associative

Read ABCA \rightarrow B \rightarrow CABC as A(BC)A \rightarrow (B \rightarrow C)A(BC), not as (AB)C(A \rightarrow B) \rightarrow C(AB)C.

Example

Partially applying a three-argument function

Let scaleAdd:integerintegerintegerinteger\text{scaleAdd}: \text{integer} \rightarrow \text{integer} \rightarrow \text{integer} \rightarrow \text{integer}scaleAdd:integerintegerintegerinteger, with scaleAdd(a,b,x)=ax+b\text{scaleAdd}(a,b,x) = a \cdot x + bscaleAdd(a,b,x)=ax+b. Work out what function is produced by scaleAdd 2 3\text{scaleAdd}\ 2\ 3scaleAdd 2 3.

  1. Apply the first argument, 2, to fix a=2a = 2a=2. The result is a function waiting for bbb and xxx.
  2. Apply the second argument, 3, to fix b=3b = 3b=3. The result is now a function waiting for only xxx.
  3. Substitute the fixed values into the rule: ax+ba \cdot x + bax+b becomes 2x+32 \cdot x + 32x+3.
  4. Therefore, scaleAdd 2 3\text{scaleAdd}\ 2\ 3scaleAdd 2 3 is the function x2x+3x \mapsto 2 \cdot x + 3x2x+3.
Common Mistake

Forgetting that partial application returns a function

add 4\text{add}\ 4add 4 is not the final numerical answer. It is a new function waiting for another integer.


4.12.1.5 Composition of functions

Definition

Composition of functions

Function composition combines two functions to produce a new function.

Given:

f:ABf: A \rightarrow Bf:AB

and:

g:BCg: B \rightarrow Cg:BC

the composition gfg \circ fgf has type:

gf:ACg \circ f: A \rightarrow Cgf:AC

This is read as “ggg composed with fff”. The important order is: apply fff first, then apply ggg to the result.

In function notation:

(gf)(x)=g(f(x))(g \circ f)(x) = g(f(x))(gf)(x)=g(f(x))
Example

Composing two functions

Let f(x)=x+2f(x) = x + 2f(x)=x+2 and g(y)=y3g(y) = y^3g(y)=y3. Find (gf)(x)(g \circ f)(x)(gf)(x) and then evaluate it when x=3x = 3x=3.

  1. Apply fff first: f(x)=x+2f(x) = x + 2f(x)=x+2.
  2. Use the result of fff as the input to ggg: g(f(x))=g(x+2)g(f(x)) = g(x + 2)g(f(x))=g(x+2).
  3. Substitute into the rule for ggg: g(x+2)=(x+2)3g(x + 2) = (x + 2)^3g(x+2)=(x+2)3.
  4. Evaluate for x=3x = 3x=3: (3+2)3=53=125(3 + 2)^3 = 5^3 = 125(3+2)3=53=125.
Common Mistake

Reversing the order of composition

gfg \circ fgf means apply fff first, then ggg. It does not mean apply ggg first.

Key Idea

Compatibility of types

For gfg \circ fgf to work, the output type of fff must match the input type of ggg. If f:ABf: A \rightarrow Bf:AB and g:BCg: B \rightarrow Cg:BC, then gf:ACg \circ f: A \rightarrow Cgf:AC.


Exam technique

In the exam

  1. When you see f:ABf: A \rightarrow Bf:AB, identify AAA as the domain and BBB as the co-domain.
  2. For partial application, state the type of the function that is returned after each argument is supplied.
  3. For composition, write (gf)(x)=g(f(x))(g \circ f)(x) = g(f(x))(gf)(x)=g(f(x)) to avoid reversing the order.
Self review

Check yourself

  • What is the difference between a function’s domain and its co-domain?
  • Why does partial function application require functions to be first-class objects?
  • If f:ABf: A \rightarrow Bf:AB and g:BCg: B \rightarrow Cg:BC, what is the type of gfg \circ fgf?
You've reached the end

Test yourself on this topic, or move on to the next guide.

Writing functional programsUp next

How was this guide?

Functional programming paradigm Revision Guide