1 Composing a function

To compose a function means to construct the mechanism that will generate an appropriate output value for any given values of the input quantities. We’re going to ignore the centuries of history that contributed to the large number of entities you might have encountered in a high-school algebra class and, instead, base our presentation in concepts and resources available in the contempary world, many of which emerged from the highly fruitful collaboration between mathematics, with its long history, and the disciplines of statistics and computing that emerged largely in the second-half of the twentieth century.

We encourage you to think about functions in the sense supported by modern computing. In the computing world, a function is a package of information together with an interface that allows you to direct the computer to calculate the output when presented with appropriate inputs. As you may know, many different computer languages have been developed. You may have heard of some; python, Javascript, C, and R are very popular. These languages provide the ability to construct and use functions, and they do so in very similar ways. For simplicity, we’ll use the notation of the R language and provide a editing and execution environment directly via these pages.

To start, let’s define a simple but entirely typical function using R. This is done by writing a sort of expression (basically, a sentence) that conveys our directions, and then directing the computer to “run” the expression. The text editor—called a chunk—that follows has been pre-loaded with a function definition. We have chosen to name the function steaminess() and to specify that the function take two inputs, one called temperature and the other rainfall. All that information—the function name and the names of the arguments, are given in line (1) of the text editor. The rest of the definition describes how to compute the function output from the input. We call this the **algorithm* for the function.

The particular algorithm for steaminess() is made-up entirely for illustration; you can ignore it except for the fact that a function output is computed by some algorithm from the inputs.

Once a function has been defined, it’s ready for use. To use a function, we write another expression that gives the name of the function values for the arguments. With the expression in place, we then signal to the computer that we want it to carry out our instructions. This is often called “running the command,” but there are many other English phrases used: “executing the function,” “invoking the function,” and “evaluating the function” all mean the same thing.

We are not going to worry at this point about how to write an algorithm. We merely want to point out that there is a definite notation for naming a function and specifying the name(s) of the input(s). As well, there is a simple notation to direct the computer to calculate the output for given input values. Metaphorically, in this first lesson in composition, we have shown you that you will make a work of art by applying paint to canvas attached to a wooden framework, and that to display the are you can hang it on the wall.

Now we turn to the heart of the matter in composing a function: figuring out in terms that make sense to you what the function ought to say. To illustrate, consider this setting: figuring out the monthly cost of a mortgage taken to buy a house. A mortgage1 is a loan, an agreement where in exchange for receiving a certain amount of money to buy a house, called the “principal,” you will pay an amount every month.

Figure 1 diagrams the quantities involved:

graph LR
  P(Loan principal P)
  R(Annual interest rate, r)
  D(Duration of mortgage, D)
  M[Monthly payment, M]
  
  P --> M
  R --> M
  D --> M
  
classDef exogenous fill:#fff,stroke-width:1px


class P exogenous
class R exogenous
class D exogenous

Figure 1: Monthly payment on a mortgage.
payment <- function(P, r, n) {
  P*r*(1+r)^n / ((1+r)^n - 1)
}

Here is what an AI query on “how to calculate mortgage payment” returns:

“To calculate a monthly mortgage payment, use the formula \[M = P \frac{r(1+r)^n}{(1+r)^n 1}\] where \(M\) is the monthly payment, \(P\) is the principal loan amount, \(r\) is the monthly interest rate (annual rate divided by 12), and \(n\) is the total number of monthly payments (loan term in years multiplied by 12).”

As it happens, the formula provided by the AI is wrong. (Wikipedia gives a correct formula.)

2 Designing a function

At the very start, you need to be definite about what will be the inputs to the function you are designing. You can read this off of the system diagram: what are the quantities at the tail end of the arrows leading into the sharp-cornered box that stands for the function you are defining.

For the sake of illustration, we will consider two (unrelated) contexts:

  1. determining the number of daily new cases at a specific point in an epidemic.
  2. determining the monthly payment on a home mortgage that you need to buy a house.

We’ll start with (a). Figure 2 shows a relevant system diagram.

graph LR
  A(Number of infectives)
  B(Number of susceptibles)
  C(infectiousness)
  D[Daily new cases]
  A --> D
  B --> D
  C --> D  

classDef exogenous fill:#fff,stroke-width:1px


class A exogenous
class B exogenous
class C exogenous

Figure 2: Daily new cases in an epidemic.

The diagram shows connections, but it is by no means a complete explanation of what we mean. For example, the diagram does not explain the operationalization for the quantities or the context into which the diagram is being placed. So let’s be explicit:

Context: A particular day in a city, say January 6, 2026 or Day 15 since the declaration of the epidemic.

Number of infectives: How many people on that day have the illness and are infectious.

Number of susceptible: How many people on that day might come down with the illness if they were exposed to an infective.

Infectiousness: Lends meaning



DON’T NEED THIS HERE.

Another deficiency in the above formats is the use of the equal sign. There are at least two different meanings to \(=\): 1) it indicates the fulcrum around which algebraic re-arrangement (for instance people \(\times\) CBR = babies) takes place. 2) it signifies that something is being defined. Our preferred notation forms for functions will avoid the use of \(=\).

We will use two forms of notation for function. The first form is a nod to traditional mathematical notation. For the CBR function, we would write: \[\text{CBR}(\text{babies, people}) \equiv \frac{\text{babies}}{\text{people}} \ .\] The mathematical symbol \(\equiv\) means, “is defined as.” The name of the function is specified on the left-hand side of \(\equiv\), coming just before the parentheses. The names of the input are listed inside the parentheses. The right-hand side of \(\equiv\) describes the algorithm used to turn the inputs into the output. Here that’s just a simple division.

The other form of notation for functions is more important and relates to computer-software syntax. There are several good reasons to emphasize such syntax:

  1. We will almost always be using software to implement our models. Doing so allows us to accomplish the tasks of algebra or calculus simply by giving the name of what we want to do.
  2. Almost all software is written in a typewriter notation consisting of letters and symbols written line-by line. In contrast, traditional math notation is really a picture where the meaning of each element is often indicated by the vertical location. Some examples of traditional notation: \[x^n \ \ \ \ \ \ \frac{\sqrt{a^2 + b^2}}{c}\ \ \ \ \ \text{or, in calculus}\ \ \ \ \frac{\partial y}{\partial t}\ \ \ \ \ \ \int_a^b y^3 dy\]

Since we will mostly be using software to perform mathematica tasks, we need to be able to express what task we want to carry out in software notations.

The software notation for the first two of the above examples is x^n and sqrt(a^2 + b^2) / c.

The issue here, of course, is how to define a function in a computer syntax. By way of example, let’s write a CBR() function in our computer notation, called R/mosaic.

CBR <- makeFun(babies / people ~ babies & people)

The <- symbol means, “is defined to be,” like the \(\equiv\) in math notation. The name to be given to the function is to the left of <-. That name, CBR here, is the only thing that goes on the left side of <-.

The right-hand side of < is more extensive. The makeFun() signals to the software that it is to construct a function (as opposed to, say, a plot or a data frame). The details of what the function is to do are placed inside the parentheses. For CBR, those details are

babies / people ~ babies & people

Once again, we have a special symbol, named “tilde,” at the core of the expression: ~. On the right-hand side of the tilde—babies ~ people—goes the name(s) of the input(s) to the function, separated by &. The algorithm for computing the function output—babies / people—is placed on the left-hand side of the tilde.

Footnotes

  1. The word stems from two ancient roots: “gage” refers to a pledge or promise, “mort” refers to death. You pay off the amount pledged with an eye toward the eventual “death” of the agreement. Related words from the same roots: “engage” and “amortization.”↩︎