Skip to content

Function Composition

Observe that curry and uncurry are functions that produce new functions from existing ones. The transformation is fairly straightforward—all we do is change how the arguments are presented to the functions—but still, the new function is not the same as the original function by virtue of taking different argument types. What other transformations can we apply to build new functions from existing ones?

Probably the most fundamental one, already discussed here, is function composition. Given two functions f :: a -> b and g :: b -> c, we can combine them to obtain a function h :: a -> c. This function passes its argument of type a to f and then produces its result of type c by passing the result of f, which is of type b, to g. The operator we use to do this is (.):

(.) :: (b -> c) -> (a -> b) -> (a -> c)
(g . f) x = g (f x)

Given that functional programming is programming by function composition, this is a rather fundamental operator. Often, we compose functions without using this operator explicitly and by using local variables in a function definition instead. Nevertheless, it is useful to have an operator that allows us to express explicitly that some function is the composition of a series of functions. We'll encounter this operator in various projects throughout this book.