Three tools. Each is a single concept; together they form the vocabulary of functional plumbing.
Terms used here (standalone):
- Currying: converting a function that takes multiple arguments into a chain of functions that
each take one argument.
f(a, b)becomescurried_f(a)(b). - Partial application: fixing some of a function’s arguments in advance, returning a function
that takes the remaining arguments.
add(3, _)fixed at3becomes a “add 3 to anything” function. - Function composition: combining two functions into one.
compose(f, g)(x) = f(g(x))—gruns first,fruns second. - Closure (from Lesson 16): a function that captures variables from its defining scope.
Part 1 — Curry add by hand
The two-argument add below takes both arguments at once. Write a curried version add_c that
takes one argument and returns a function that takes the second.
def add(x, y):
return x + y
# Target: add_c(3)(4) == 7
def add_c(x):
???
Then use add_c to create add10 — a function that adds 10 to anything.
Part 2 — Partial application with functools.partial
Python’s functools.partial fixes some arguments of any function:
from functools import partial
add10 = partial(add, 10) # add(10, ?) — first arg fixed at 10
add10(5) # 15
Given:
def power(base, exponent):
return base ** exponent
Use partial to create square (exponent=2) and cube (exponent=3). Then create powers_of_2
(base=2).
square(5) # 25
cube(3) # 27
powers_of_2(8) # 256
Part 3 — Compose and apply
Write compose(f, g) (you saw it in Lesson 13; write it from scratch here).
Then use it and your Part 1/2 results to build a pipeline function double_then_square using only
compose, partial, and power (no arithmetic operators directly, no lambdas).
double_then_square(3) # (3*2)^2 = 36
double_then_square(5) # (5*2)^2 = 100
Stretch — compose for N functions
Write compose_all(fns) that composes an arbitrary list of functions (right-to-left, so the last
function in the list runs first).
compose_all([str, abs, lambda x: x - 100])(42) # str(abs(42 - 100)) = str(58) = "58"