math toy collection

Thinking About Functions

Kirby Urner
7 min readOct 3, 2019


One of the perennial questions in mathematics classes across the land is “what is this good for?” as in “when will I need this?”.

At least one answer is obvious: all this function notation and conceptualization, wherein you pass arguments from the domain, getting results in some range, is a pretty healthy diet — or good workout, depending on your metaphor of choice.

“Why?” you may ask. “Why do I care about functions and function notation?”.

calculator of tomorrow

I’ve written about this “calculator of tomorrow” (depicted above) in more detail elsewhere. My purpose in sharing this exhibit is to simply acknowledge that writing computer languages often entails defining things called “functions” which in older languages were maybe called “subprocedures” or “subroutines”.

You’re correct if you’re thinking “but a function in the mathematical sense is not the same thing as a subroutine” and that’s somewhat what this story is about. Remember though, we’re saying “function” now in computer-speak too, and we do have the ability to make them follow a more formal set of rules, set forth in math class.

What you learn in mathematics class, and your teacher is not lying, is that a “real” (as in bonafide) function always gives the same output for the same input. The metaphor is often that of a map, with arrows pointing from where you start in some domain, and where you end up in some range of possible outputs. The function is what takes you there.

If all this “domain and range” stuff reminds you of ballistics and firing cannon balls, that certainly goes with the territory, in terms of our history. Soldiers had lookup tables and the idea was if you dial in the relevant settings, not neglecting for wind speed, you might have a decent chance of hitting a target. Functions were (and are) all about: if I give you this, I will get back that: the work you were intended to perform.

Shot and shell piled under the walls of Fortress Monroe (Harper’s Weekly, June 29, 1861, public domain)

Think of boarding an airplane. You have read the appropriate signage and know where it’s going. Where you end up is not some random outcome, not some amazing coincidence. That is not in the world of mathematics. In the real world, we’re more likely to assign probabilities, because the real world is less predictable than a purely logical one. You may have noticed.

The great thing about a mathematical function, is if I give you all the inputs, and leave nothing to chance, I’m guaranteed a specific result. It’s that “leaving nothing to chance” that might prove the awkward bit. Are there limits to our ability to control? Sometimes those limits seem non-obvious, even after we’ve discovered them.

Well, it does turn out that “a function” in a given computer language, might not quite obey all these rules, because the language itself allows a kind of “sloppiness” — by design. The meaning of function does inherit from other contexts, and computer science has this notion of “scope”. Changes in the global scope may affect a function’s output, and yet these changes are not reflected in the argument inputs.

Depending on environmental factors, a function might take you to different places, even though you see the input as the same in both cases. That’s unacceptable in the mathematical universe, which is quite strict about what it takes to be a function.

Why do computer languages permit such “sloppiness” you might ask? Many of them don’t, at least not on paper. They prevent the programmer from polluting a local space, where the same machinery always operates, with no interference from “extraneous ideas” (or “hidden globals”) that could not be accounted for (tracked, easily monitored) within the bowels of this particular function. We often say such “polluted” programs are “difficult to reason about” and that’s true, they often are.

In other words, if all the logic you need, to know the results of a function, given specific inputs, isn’t right there in front of you, then it can’t easily be trusted as a “real” function. Functional programming promises transparency and the ability to reason about programs more as if they were formal mathematical proofs.

Short of unforeseen circumstances outside the ability of a computer language to dictate (such as CPU time allocated by the operating system), a purely functional program might be provably correct and therefore a perfect fit for specific circumstances. Indeed.

Here’s a real world example of what might happen in Codesters, a coding platform: you will write a little song with stage.wait(0.3) seconds between each musical note; but then, as you scroll the window up and down while it plays the score, you notice a speed-up and slow-down in performance.

The notes are not as metronomic as before. Speed varies, in ways “mathematical music” never should. Something “environmental” is causing our functions to vary output in response to the same input.

There’s a potential for confusion here. We might say that the program itself is logically deterministic, given what it is able to take into account, grammatically, as a language. It’s not that new arguments get added or introduced by means of globals (environmental values defined in the program).

Rather, the speed of the CPU, or the amount of time the CPU has for this program, is not controlled by the grammar of the language. Even a functionally pure language has to deal with the “environment” the computer language itself does not define. Especially with music, real time performance matters. We hear the differences quite pronouncedly.

In sum: yes, that stuff about functions you’re learning in math class will come in handy later.

You’ll be thinking about those rules, for mapping domain to range elements, and whether they obey the criteria set forth in math class, for them (these rules) to be actual functions, and not mere “relations” — another form of mapping, a superset of which functions are a part. Relations may be less predictable and deterministic.

{{1,2}, {2,1}, {1,1}, {0,0}} may be interpreted in various ways, as a set of sets for instance. That’s what it says in Python (actually not quite, see below).

Tricky: OK, so if sets contain only unique values, no duplicates, and if {1,2} and {2,1} are considered “synonymous sets”, then should not the above set be ungrammatical in Python? Sets don’t contain duplicates remember. The left to right order of set members should not be a consideration when singling them out.

Indeed, what I wrote above cannot be read as pure Python. {0,0} for starters, contains duplicate values. Not only that, sets can’t be members of sets; they’re too mutable.

In [8]: {{1,2}, {2,1}, {1,1}, {0,0}}

Traceback (most recent call last):

File “<ipython-input-13–4088db72ab8c>”, line 1, in <module>

{{1,2}, {2,1}, {1,1}, {0,0}}

TypeError: unhashable type: ‘set’

Fortunately, Python has an “immutable set” type, the frozenset… So, cutting and pasting (again) from some I-Python IDE (Spyder in this case):

In [9]: it = map(frozenset, ({1,2}, {2,1}, {1,1}, {0,0}))

In [10]: {it for it in it} # maybe not best practice but it works

Out[10]: {frozenset({1}), frozenset({0}), frozenset({1, 2})}

That’s about as close as we get, and yes, {1,2} and {2,1} got collapsed into just the one element.

On In [10] I unnecessarily overused “it” hence my comment.

More readable:

In [11]: it = map(frozenset, ({1,2}, {2,1}, {1,1}, {0,0}))

In [12]: {elem for elem in it} # better

Out[12]: {frozenset({1}), frozenset({0}), frozenset({1, 2})}

Back to {{1,2}, {2,1}, {1,1}, {0,0}} and forget Python for now: if we consider the left number of each pair a domain element, and each right number a corresponding range element, then this raises doubts about “functionhood” right?

Our mapping has become too unpredictable. If I use 1 for my input, what will that give me? Do I know for sure?

Do you see the issue? The domain element 1 maps to range element 2 in the leftmost pair {1, 2}, but 1 maps to 1 in the 1st from last {1, 1}.

That couldn’t be a function then. We could call it a relation.

However in Python we ignore order in mappings so {1,2} and {2,1} are essentially synonymous.

All of the above healthy thoughts play into learning Python or just about any coding language. JavaScript is all about functions.

You might one day learn about “object oriented” languages and find they’re apparently locked in mortal combat with more “functional” languages (depending on who is telling the story). One could say all the languages learn from one another. We’re gradually teaching ourselves about what works best.

Mathematics is much the same way. We evolve and/or morph our ideas to help us get the job done, whatever the job. Sometimes the job is just to solve a nagging problem, whether or not we see the practical value in doing so.

If your mathematics teacher has some time to show you Codesters, instead of a calculator for example, or in addition to one, then you’ll get to see more of these connections.

Having a math teacher explain functions to you, irrespective of any particular computer language, is valuable.

Be glad you’re getting that now, in your mathematics class.

However, don’t be afraid to take a peek at the computer languages that might be coming. I’ve heard Pharo looks pretty interesting. Or take a look at J.

from Martian Math