Higher-order Functions and Set Theory
Higher-order function (HOF) is a type of nested function that offers a higher level of abstraction than ordinary functions, where instead of taking primitives or variables as arguments (parameters) and outputting objects, functions are taken in and output by HOFs.
The subtleties between a function composition and HOF can be shown through the syntax of Python, which can result in different behaviours depending on how we close the parentheses.
A classic example is demonstrated as follows.
def thrice(f):
return lambda x: f(f(f(x)))
add1 = lambda x: x + 1
x = thrice(thrice(add1))(0) # 9
y = thrice(thrice)(add1)(0) # 27
In the example above, x
will output 9
because the defining line of code is interpreted ‘right-to-left’ (like function composition), first composing the add1
function thrice to produce a function equivalent to lambda x: x + 3
, then composing the first output thrice to produce a function equivalent to lambda x: x + 9
, thus 0 + 9 = 9
.
As for y
, it will output 27
because it is defined ‘left-to-right’, first composing the thrice
function itself three times, resulting in an HOF that effectively composes an input function times, which then takes in the function add1
to produce a function equivalent to lambda x: x + 27
, and finally we get 0 + 27 = 27
.
Higher-order functions are closely related to mathematics, in the sense that they enable the implementation of operators in mathematics, as well as a family of functions, using code.
For example1, in set theory, we can define a family of functions , which itself is also considered a function from . This operator takes in a function and outputs another function that takes in whatever takes in and outputs whatever outputs plus one.
Phrased in a set-theoretic language as ‘pure’ as possible, is defined as
An HOF implementation of in Python can then look like the following:
# The following type hints are to indicate that the functions are in N^N, and are unnecessary for practical purposes.
from typing import Annotated, Callable
from annotated_types import Ge # requires additional pip install: https://pypi.org/project/annotated-types/
def F(f: Callable[Annotated[int, Ge(0)], Annotated[int, Ge(0)]]) -> Callable[Annotated[int, Ge(0)], Annotated[int, Ge(0)]]:
def output(n: Annotated[int, Ge(0)]) -> Annotated[int, Ge(0)]:
return f(n) + 1
return output
f = lambda x: x + 1
F(f)(0) # 2
Footnotes
-
This example is taken from the lecture notes of the Set Theory course conducted during the Fall 2022 semester by Dilip Raghavan in National University of Singapore. ↩