Exploring Languages
with Interpreters
and Functional Programming
Chapter 80
H. Conrad Cunningham
04 April 2022*
Browser Advisory: The HTML version of this textbook requires a browser that supports the display of MathML. A good choice as of April 2022 is a recent version of Firefox from Mozilla.
Students studying from this textbook should already have sufficient familiarity with the relevant mathematical concepts from the usual prerequisite courses. However, they may need to relate the mathematics with the programming constructs in functional programming.
The goal of this chapter is to review the mathematical concepts of functions and a few other mathematical concepts used in these notes. The concept of function in functional programming corresponds closely to the mathematical concept of function.
TODO: Add discussion of logic needed for specification and statement of laws?
TODO: Add appropriate citations.
Several of the examples in these notes use natural numbers.
For this study, we consider the set of natural numbers to consist of 0 and the positive integers.
Inductively, if and only if one of the following holds
where is the successor function, which returns the next element.
Furthermore,
The natural numbers thus form a totally ordered set in conjunction with the binary relation (less or equal). That is, the relation satisfies the following properties on set :
It is also a partial ordering because it satisfies the first three properties above.
For all , we can define the other ordering relations in terms of , , and as follows:
As we have studied in mathematics courses, a function is a mapping from a set into a set such that each element of is mapped into a unique element of .
If is a function from into , then we write:
We also write the equation
to mean that the value (or result) from applying function to an element is an element .
If a function
and , then we say that is a partial function from to and a total function from to . That is, there are some elements of on which may be undefined.
Informally, a recursive function is a function defined using recursion.
In computing science, recursion is a method in which an “object” is defined in terms of smaller (or simpler) “objects” of the same type. A recursion is usually defined in terms of a recurrence relation.
A recurrence relation defines an “object” as some combination of zero or more other “objects” for . Here means that is smaller (or simpler) than . If there is no smaller object, then is a base object.
For example, consider a recursive function to compute the sum of the first natural numbers.
We can define a recurrence relation for with the following equations:
, if
, if
For example, consider ,
We can give two mathematical definitions of factorial, fact and fact’, that are equivalent for all natural number arguments.
We can define fact using the product operator as follows:
fact
We can also define the factorial function fact’ with a recursive definition (or recurrence relation) as follows:
fact’, if
fact’ fact’, if
It is, of course, easy to see that the recurrence relation definition is equivalent to the previous definition. But how can we prove it?
To prove that the above definitions of the factorial function are equivalent, we can use mathematical induction over the natural numbers.
Mathematical induction: To prove a logical proposition holds for any natural number , we must show two things:
The assumption is called the induction hypothesis.
Now let’s prove that the two definitions fact and fact’ are equivalent.
Prove For all natural numbers , fact fact’.
Base case .
fact
{
definition of fact (left to right)
}
{
empty range for
,
1 is the identity element of
}
{
definition of fact’ (first leg, right to left)
}
fact’
Inductive case
.
Given induction hypothesis
fact
fact’,
prove
factfact’.
fact’
{
definition of fact (left to right)
}
{
,
so
term exists, split it out }
{
definition of fact (right to left)
}
fact
{
induction hypothesis }
fact’
{
,
definition of fact’ (second leg, right to left)
}
fact’
Therefore, we have proved fact fact’ for all natural numbers . QED
In the inductive step above, we explicitly state the induction hypothesis and assertion we wish to prove in terms of a different variable name ( instead of ) than the original statement. This helps to avoid the confusion in use of the induction hypothesis that sometimes arises.
We use an equational style of reasoning. To prove that an equation holds, we begin with one side and prove that it is equal to the other side. We repeatedly “substitute equals for equal” until we get the other expression.
Each transformational step is justified by a definition, a known property of arithmetic, or the induction hypothesis.
The structure of this inductive argument closely matches the structure of the recursive definition of fact’.
What does this have to do with functional programming? Many of the functions we will define in these notes have a recursive structure similar to fact’. The proofs and program derivations that we do will resemble the inductive argument above.
Recursion, induction, and iteration are all manifestations of the same phenomenon.
A function
is called a binary operation on . We usually write binary operations in infix form:
a a’
We often call a two-argument function of the form
a binary operation as well. We can write this two argument function in the equivalent curried form:
The curried form shows a multiple-paramenter function in a form where the function takes the arguments one at a time, returning the resulting function with one fewer arguments.
Let be a binary operation on some set and , , and be elements of . We can define the following kinds of properties.
Operation is closed on if and only if for any . That is, the operation is a total function on its domain.
Operation is associative if and only if for .
Operation is commutative (also called symmetric) if and only if for .
An element of set is
An identity of an operation is called a unit of the operation.
An element of set is
If is the identity of and for some and , then
Elements and are inverses of each other if .
An element of set is idempotent if .
If all elements of are idempotent with respect to , then is called idempotent.
For example, the addition operation +
on natural numbers
is closed, associative, and commutative and has the identity element 0.
It has neither a left or right zero element and the only element with a
left or right inverse is 0. If we consider the set of all integers, then
all elements also have inverses.
Also, the multiplication operation *
on natural numbers
(or on all integers) is closed, associative, and commutative and has
identity element 1 and zero element 0. Only value 1 has a left or right
inverse.
However, the subtraction operation on natural numbers is not closed, associative, or commutative and has neither a left nor right zero. The value 0 is subtraction’s right identity, but subtraction has no left identity. Each element is its own right and left inverse. If we consider all integers, then the operation is also closed.
Also, the “logical and” and “logical or” operations are idempotent with respect to the set of Booleans.
An algebraic structure consists of a set of values, a set of one or more operations on those values, and properties (or “laws”) of the operation on the set. We can characterize algebraic structures by the operations and their properties on the set of values.
If we focus on a binary operation on a set , then we can define various algebraic structures based on their properties.
If is closed on , then then and A form a magma.
A magma in which is an associative operation forms a semigroup.
A semigroup in which has an identity element forms a monoid.
A monoid in which every element of has an inverse forms a group.
A monoid in which is commutative forms a commutative monoid (or Abelian monoid).
A group in which is commutative forms an Abelian group.
For example, addition on natural numbers forms a commutative monoid and on integers forms an Abelian group.
Note: Above we describe a few common group-like algebraic structures, that is, algebras with one operation and one set. If we consider two operations on one set (e.g. on ), then we have various ring-like algebraic structures. By adding other operations, we have various other kinds of algebraic structures. If we consider more than one set, then we moved from a single-sorted (or first-order) algebra to a many-sorted algebra.
TODO: Add
I adapted and revised much of this work in Summer and Fall 2016 from Chapter 2 of my Notes on Functional Programming with Haskell [1].
In Summer and Fall 2017, I continued to develop this material as a part of Chapter 1, Fundamentals, of my 2017 Haskell-based programming languages textbook.
In Spring and Summer 2018, I reorganized and expanded the previous Fundamentals chapter into four chapters for the 2018 version of the textbook, now titled Exploring Languages with Interpreters and Functional Programming. These are Chapter 1, Evolution of Programming Languages; Chapter 2, Programming Paradigms; Chapter 3, Object-based Paradigms; and Chapter 80, Review of Relevant Mathematics (this background chapter).
In Spring 2019, I expanded the discussion of algebraic structures a bit.
I retired from the full-time faculty in May 2019. As one of my post-retirement projects, I am continuing work on this textbook. In January 2022, I began refining the existing content, integrating additional separately developed materials, reformatting the document (e.g., using CSS), constructing a unified bibliography (e.g., using citeproc), and improving the build workflow and use of Pandoc.
I maintain this chapter as text in Pandoc’s dialect of Markdown using embedded LaTeX markup for the mathematical formulas and then translate the document to HTML, PDF, and other forms as needed.
TODO: Add