In a past post we introduced functions and their advantages. In this post, we will extend on the functionality of functions by introducing** higher-order functions.** Particularly, we’ll see how to include functions among the parameters of a function with an example.

## Higher-order functions

A higher-order function is a function that either:

- Accepts a function among its parameters.
- Returns a function.

In other words, a higher-order function is a function that deals with other functions in some way.

### Why are they important?

We can see higher-order functions as an extra “tool” in our programming tool-box. This extra tool allows us greater expressive possibilities while using functions.

Let’s see an example.

## Accepting a function as a parameter

Let’s say we have a function with two parameters: `f(a, b)`

. Usually, the parameters `a`

and `b`

are variables (numbers, strings, lists, etc). But if any of `a`

or `b`

is a function, then `f`

is a **higher-order procedure**.

As a concrete example, let’s say we want to filter even values in a list. We could do it with the following function:

def filter(numbers): result = [] for number in numbers: if number % 2 == 0: result.append(number) return result

The parameter `numbers`

is a list of numbers. For example, if we call `filter([1, 2, 3, 4])`

, it will return the list of even numbers `[2, 4]`

.

Now, let’s say we want to filter odd numbers instead. We can do it with minor changes on the test condition to append elements to the `result`

list:

... if number % 2 == 1: ...

See that the general structure of `filter`

has not changed. In more general terms, the `if`

clause establishes the condition that has to be satisfied in order to include a number in the filtered list. This is the motivation we needed to create higher-order functions. Let’s see how to generalize `filter`

.

### Defining higher-order functions

Instead of changing the test performed by the `if`

clause at each time, we can generalize it by using a `test`

function:

... if test(number): ...

`test`

is a function that returns `True`

when its argument satisfies a certain condition and `False`

otherwise. To include this function inside `filter`

‘s body, we just need to include it among its parameters as we did for `numbers`

:

def filter(numbers, test): result = [] for number in numbers: if test(number): result.append(number) return result

See that the `test`

parameter is a function called at the `if`

clause. Congratulations! You have just defined a higher-order function. It wasn’t difficult, right? We just included the function parameter among the other parameters and then used it in the function’s body.

A general recipe for higher order functions of this kind would be:

def function(param_1, ..., func, ...): # Function's body # It's possible to call func(...) here.

Among the paramaters `param_1`

, … we have a function parameter: `func`

. By including it among the other parameters, we have now the option of using it inside function’s body with all the advantages that that entails.

Let’s see how to apply it to filter even values. We can test if a number is even with:

def even(n): return n % 2 == 0

If we call `even(10)`

, it will return `True`

. If we call `even(7)`

, it will return `False`

, and so on.

Finally, to filter even numbers we call:

>>> filter([1, 2, 3, 4, 5], even) [2, 4]

We’re calling `filter`

with the arguments `numbers = [1, 2, 3, 4, 5]`

and `test = even`

.

### What’s the big deal?

While this example may seem trivial, we have in fact defined a very powerful function. Here are some examples:

# Helper functions def odd(n): return n % 2 == 1 def greater_5(n): return n > 5 def is_a(char): return char == 'a'

>>> filter(numbers, odd) [1, 3, 5, 7, 9] >>> filter(numbers, greater_5) [6, 7, 8, 9] >>> filter(['a', 'b', 'c'], is_a) ['a']

Using `filter`

, we’re able to perform any test on a list of numbers. Here we have seen tests using the `odd`

and `greater_5`

functions to filter odd values and numbers greater than 5, respectively. Similarly, by just defining a suitable function, we could filter prime numbers, perfect squares, etc.

In fact, we can apply the filter function to any kind of list! See that the last example was passed a list of characters: `['a', 'b', 'c']`

. We filtered it with `is_a`

to get only the `'a'`

characters present in the list.

We have seen how to include functions among the parameters of another function, creating higher-order functions. This additional feature allows us a wider range of expressive capabilities using functions. In a future post, we will see how to return functions using functions, a different kind of higher-order function.