Data Constructors In Math
This is a short post — nothing deep or complex, but just a simple observation. Often, distinctions that are made in programming language reflect ideas that already exist, but that we tend to be less clear about, in other contexts, too!
We make an observation about Haskell…
In Haskell programming, there’s a distinction between a variable, which starts with a lower-case letter, and a data constructor, which starts with an upper-case letter. For example, consider the following declaration of a familiar data type.
data Bool = True | False
This defines the type Bool, and its two values True and False. They are data constructors. On the other hand, we can also write this:
true = True false = False
This defines two new symbols, true and false (note the lower-case letters) that mean the same thing as True and False…. sort of. They mean the same thing only when they occur in the context of an expression. Still, there remains a difference: True and False can occur in pattern matching, which true and false cannot.
At first glance, this looks like a rather arbitrary distinction. Pattern matching, after all, is a particular Haskell language construct. Indeed, there are plenty of languages without the distinction. But is it really all that arbitrary?
Ultimately what’s happening here is that Haskell has provided us with syntax to say that True and False are defined on the fly by virtue of their occurring inside the definition of Bool. Furthermore, since they have no other definition to tell us otherwise, we’re left to assume that values built from different data constructors are distinct, as are the values obtained by applying any one data constructor to different arguments.
While we wrestle with these issues in Haskell programming, mathematics students in an algebra course are tackling a different problem: the lecture notes for their courses don’t seem to make much sense! They start out with some analysis, where they come across the following:
Consider the sequence obtained by multiplying corresponding elements of x and y. Let …
This they understand: Here x and y are essentially maps from the natural numbers to values of some sequences. These maps were defined earlier, and now specific values of them are obtained by applying them to particular natural numbers. Now on to algebra, where perhaps they are learning about Leavitt algebras, and their notes say:
The Leavitt algebra L(1,n) is generated by together with relations…
Almost exactly the same wording occurs here ( for certain values of i), but at first the students are very confused. Here, there are no maps x and y that were previously known. Our hypothetical students are left to figure out on their own what the x and y might mean.
Hopefully, these students eventually realize that here, the x and y are is being defined right here alongside L(1,n). Before that sentence, x and y meant nothing in particular. From context, one infers that they are maps from numbers to L(1,n). Because no one mentioned otherwise, one is supposed to assume that values taken by x and y are distinct, as are the values of each of x and y when applied to different arguments…
Now we get to the point. What’s happened here is that our hypothetical mathematics students have encountered the difference between a variable and a data constructor. Their analysis notes were using variables, while their algebra notes were using data constructors. But in the mathematical world, there is no distinct notation to clarify what is going on!
Perhaps it would be made clearer if we rewrite their notes in Haskell. In the analysis context:
x :: Int -> Double y :: Int -> Double p :: Int -> Double p i = x i * y i
While in the algebra context, we have:
data LeavittGenerator where X :: Int -> LeavittGenerator Y :: Int -> LeavittGenerator
The data constructors are now clearly something different, as they begin with capital letters!