Functional Programming illustrated in Python: Part 1

Simple function composition

Brian Candler
3 min readOct 20, 2020

From the Functional Programming illustrated in Python series

Functions calculate values from values. In the simplest case, to combine functions you would take the output from one function and use it as the input to another function.

I am going to take a very simple example:

  • The first function f() calculates the square of its input
  • The second function g() doubles its input
  • The third function h() adds one to its input

By applying the functions in this order, we can calculate 2x²+1.

This is very simple. We start with an input value of 4, square it (16), double it (32), and add one — giving the answer 33. It’s direct application of functions.

Using this notation, we have to nest f inside g and g inside h (and h inside print). The evaluation happens from inside to outside, and hence apparently from right to left. A clearer alternative will be introduced shortly.

For now, you might prefer to bind the intermediate results to variables, so that the flow is from top to bottom, like this:

Or you might not, since you now have the extra variables to think about.

Composition

Let’s build a new, single function which applies f, g and h in the correct order. We could write this directly:

def hgf(v):
return h(g(f(v)))

But that means writing new code every time we want to combine a set of functions. Can we do this in a more reusable way? Yes we can, by means of “function composition” — an operation which combines functions into a new function.

The key part is the function compose(f1, f2). This accepts two functions as arguments, and returns a single new function, which when invoked, applies f2 and then f1 to a value. The returned function can itself be composed with another function, and so on. We end up with a single function hgf.

This is such a powerful idea that “functional” languages have composition built-in: in Haskell this would be h . g . f

It will become important later.

Chaining the functions

Finally, I’ll show a way to make the data flow linearly from left to right, instead of inside-out and right-to-left.

The trick here is to place the initial value inside a wrapper object, which I’ve called class Value.

On that wrapper I’ve defined a >> operator¹, where v >> f calls f(unwrapped-v).

In Python this is done by giving the class an operator method: the >> operator normally means “shift bits right”, so the method is called __rshift__.

I also made each function wrap its return value, so these values can be chained².

Et voilà, functions are now invoked so that the value is passed from left to right, as if in a pipeline, without having to assign to intermediate variables.

The operator this >> that means “evaluate this, then apply that to the value”. This is known as a “continuation passing” style: instead of asking a function to return a value directly, you ask it to call some other function that you provide.

The last two lines can be simplified further to:

Value(4) >> f >> g >> h >> print

Can you see why? The final >> operator acts on the wrapped value on its left, and calls the function on its right (i.e. print) with the unwrapped value as its argument. Of course, this does introduce an impure function into what was previously a pure functional pipeline.

If you split the lines, you get a familiar top-to-bottom flow:

(
Value(4) >>
f >>
g >>
h >>
print
)

However, this is not just a way to make a functional program look pretty. This technique can be expanded into a more powerful way of combining functions that I’ll introduce in the next article.

[1] I really wanted to use the >>= operator, which is what Haskell uses, but Python doesn’t allow that operator to be redefined.

[2] The astute reader will have noticed that I could have re-wrapped the return value inside the __rshift__ method as well. However, when you develop this pattern so that the wrapper carries multiple values, then the user’s function will need to return a wrapped value.

--

--