SLIDE 1 / 10
CSZone.co.uk
Click anywhere to advance · Arrow keys also work
AQA 7517 · Paper 2 · 4.12.1b

Closures, Currying
& Lazy Evaluation

Function composition · partial application · tail recursion · lazy vs eager evaluation

WHAT YOU'LL LEARN
Closures · currying · partial application · function composition · tail recursion · lazy evaluation
AQA SPEC LINK
4.12.1 — Closures, currying, partial application, function composition, tail recursion, lazy evaluation
Closures

Closures

A closure is a function that captures variables from the environment in which it was defined, even after that environment has gone out of scope.
-- A function that creates an adder closure
makeAdder n = \x -> x + n

add5 = makeAdder 5 -- n is captured as 5
add5 10 -- Result: 15
add5 3 -- Result: 8
The inner function "closes over" the variable n, remembering its value
Currying

Currying

Currying transforms a function that takes multiple arguments into a chain of functions each taking a single argument.
-- Uncurried: takes a tuple (pair)
add (x, y) = x + y

-- Curried: takes one argument at a time (Haskell default)
add x y = x + y
-- add 3 4 = (add 3) 4 = 7
-- (add 3) is a partial application!
In Haskell, all functions are curried by default — f x y really means (f x) y
Partial Application

Partial Application

Partial application is applying a curried function to fewer arguments than it expects, producing a new function with some arguments fixed.
multiply x y = x * y

triple = multiply 3 -- partial application: x=3, y still needed
triple 5 -- Result: 15
triple 10 -- Result: 30

-- Used with map:
map (multiply 2) [1,2,3] -- [2, 4, 6]
Function Composition

Function Composition

The . operator composes two functions: (f . g) x = f (g x). Apply g first, then f to the result.
double x = x * 2
increment x = x + 1

-- Compose: double after increment
doubleAfterInc = double . increment
doubleAfterInc 3 -- increment 3 = 4, then double 4 = 8

-- Pipeline using composition:
(double . increment . double) 5 -- = double(increment(double 5)) = 22
Tail Recursion

Tail Recursion

A function is tail recursive if the recursive call is the last operation performed. The compiler can optimise this into a loop (tail call optimisation — TCO), avoiding stack overflow.
-- Not tail recursive: multiplication after recursion
factorial 0 = 1
factorial n = n * factorial (n-1)

-- Tail recursive: accumulator carries the result
factTail 0 acc = acc
factTail n acc = factTail (n-1) (n*acc)
factorial n = factTail n 1
Lazy Evaluation

Lazy vs Eager Evaluation

Eager (Strict) Evaluation
Evaluate all arguments immediately when a function is called. Most languages (Python, Java). Can waste work if result is never used.
Lazy Evaluation
Evaluate expressions only when their value is actually needed. Haskell uses lazy evaluation by default. Enables infinite data structures.
-- Haskell: infinite list is fine — only evaluated as needed
naturals = [1..]
take 5 naturals -- [1, 2, 3, 4, 5]
Lambda Functions

Lambda (Anonymous) Functions

A lambda function (anonymous function) is a function without a name, written inline. Denoted with \ in Haskell (looks like λ).
-- Named function:
square x = x * x

-- Equivalent lambda:
\x -> x * x

-- Used inline with map:
map (\x -> x * x) [1,2,3,4] -- [1, 4, 9, 16]
Lambdas are useful for short, one-off functions — no need to give them a name
AQA Exam Style

Practice Question

AQA 7517 — Paper 2 Style
(a) Explain what is meant by currying in functional programming. [2]
(b) The function multiply x y = x * y. Write an expression using partial application to create a function that doubles its argument. [2]
(c) Explain the difference between lazy evaluation and eager evaluation. Give ONE advantage of lazy evaluation. [3]
[7 marks]
2 marks
(a) Currying transforms a function that takes multiple arguments into a series of functions each taking a single argument [1]; so add x y becomes (add x) applied to y — the function can be partially applied [1]
2 marks
(b) double = multiply 2 [1]; (applying it: double 5 = 10) [1]
3 marks
(c) Eager: expressions are evaluated as soon as they are bound [1]; Lazy: expressions are only evaluated when their value is actually needed [1]; Advantage: allows infinite data structures / avoids computing values that are never used / can improve performance [1]
Summary

Key Points to Remember

Closure — function that captures variables from its defining environment
Currying — function of n args → chain of n single-arg functions; (f x y = (f x) y)
Partial application — fix some arguments of a curried function to get a new function
Function composition — (f . g) x = f(g(x)); build pipelines of functions
Tail recursion — recursive call is last op; compiler can optimise (no stack overflow)
Lazy evaluation — evaluate only when needed; enables infinite structures (Haskell default)
🎉 Lesson complete — move to the quiz!