Quick note, because I talk about math and programming, I use the term ‘function’ to refer to a function in the mathematical sense and the term ‘method’ to refer to a function in a programming sense :)
Disclaimer, I am not a mathematician, I just enjoy studying it for fun. If I have been inaccurate in any of my assertions, please leave a comment and I will do my best to correct it.
This is a post about math. I am a programmer, but I love studying math as a hobby. I especially love making connections between computational science (my field) and the broader field of mathematics. My purpose in this post is to help you discover some of those basic relations as well. I promise it won’t be too hard, if anything it should mostly be review. So, let’s jump into some math!
Alright, for those of you still with me, let’s take a journey back to your high-school math class. You’re learning about algebra and might be a little confused about why all the sudden we are using letters instead of numbers. At some point, your teacher introduces a concept to the class, which will come to be crucial to your next few years of mathematical study. The function: f(x).
If you need a refresher, a function is a mathematical construct which takes an input, works some magic, and returns an output. For now, we don’t really care what that magic is or how it works. All we care is that a function f, when given an input x, returns an output y. This is commonly written as f(x) = y. In math, we often visualize functions as graphs on a coordinate plane. This allows us to quickly and intuitively understand what a function does when given a specific input. Some function outputs are quite simple, like y = f(x) = x:
Or functions can be more complex (pardon the pun), like the Riemann Zeta function:
Note: This video is very mathy, not for the faint of heart, but if you’re reading this post, you might find it rather interesting :)
Either way, the concept of a function is rather straightforward. You give it an input, it gives you an output based on that input. Within math, we refer to the set of all possible inputs to a function as the domain of a function, and the set of all possible outputs as its co-domain. There are two possible ways a function can relate its domain to its co-domain. Let’s take a quick look at them:
- One-to-One (Also called an injective function): This means that for every input to a function, there is a unique output that can only be produced by that input; there is no overlap.
- Onto (also called a surjective function): This means that every input to a function maps to an output in the co-domain. Multiple inputs could produce the same output.
There is one last concept we need to cover before moving on, the range (also sometimes called the image) of a function. The range of a function defines the subset of the co-domain that is actually reachable by the function’s output. For example, the domain and co-domain of the function sin(x) are the real numbers (ℜ). The sin function takes a real number as input and produces a real number as output. However, the range of sin(x) is [-1,1]. No matter what real number value you give it, the sin function will always produce a number in it’s range.
I really love the images Wikipedia uses to demonstrate how the domain relates to the co-domain, because it is rather intuitive to make the next step in understanding. Realizing that the arrows represent the “magic” that happens inside of a function, I believe it is quite intuitive to begin to understand function mapping. What I mean by that, is that every function input can be mapped to a function output. In our onto example, the value 1 can be mapped to the value D, 2 to B, and 3 and 4 to C. The extra visualization helps us understand that it is the function that performs that mapping of values.
For you functional programmers out there, I hope that the word mapping triggered something inside of your mind. Most functional languages have a method called map, which takes a collection of items and a function and returns a new collection having applied that function to each item in the collection.
Do you see the connection to what we just talked about with mathematical functions? You give the map method a function and (a subset of) its domain (the collection of items). The map method will then return back the resulting co-domain of that function! How cool is that?! By taking a quick look at the core concepts of mathematical functions, we’ve intuitively gained an understanding of how the map method works in functional programming!
So, for a math nerd like me that’s interesting, but I’m sure that many of you are asking if this is useful to know as a programmer. I would argue that it is. Let’s look at those two types of relations again, injective and surjective. When you are programming, whether you are writing complex algorithms to solve hard computational problems or doing simple web development, I would argue that it is important for you to understand how the methods you create behave. Are they injective or surjective? Is the range the same size as it’s co-domain? Understanding how your methods transform their inputs will help you eliminate bugs faster, write better tests, and understand your own code on a deeper level.
I hope that this quick look at functions inspires you to take a closer look at the programs you are writing. I really believe that if you take the time to understand the mathematical concepts behind the essential concepts in programming, it will make you a better developer.