School of Athens, where mathematics was born

Functional Programming has been gaining popularity in the last years because of it’s many features that can benefit our code in different ways, like monoids, functors, monads (don’t panic) and other fancy named stuff.

One of them, and maybe the one of the simplest ones to understand are Algebraic Data Types (or simply ADTs) and as many of other functional programming things I mentioned earlier, there’s a big chance you have been using them on daily basis without acknowledging it.

I’ll be using TypeScript/Flow type annotations to better express the essence of ADTs. Also they both kinda have ADTs built in them.

There are two types of ADTs:

Product types

Sum types

Products of types represent a conjunction, “and,” of those types. So lets define an example Product type:

Pair is the product of types U and V , which are just placeholders and can be any type like: Pair<Boolean, Number> or Pair<String, Function> , etc.

Looks familiar right? But it’s not only about pairs, we can define Infinite numbers of different product types:

You might ask: Why make things difficult by calling classes as simple as Pair<U,V> or Person Algebraic or Product?

Well, let’s remember what product was in algebra we were taught at school. It has several properties:

Symmetry: a * b = b * a , is the same true for Product type?

lets define a operator ~~ for the sake of this article. If we say A ~~ B it means A is not equal to B , but they contain same information, they are “equal-ish” or if we look at fancy terms they’re isomorphic (wiki). We can define a function from A to B and in reverse.

So, You can say that Pair<U, V> ~~ Pair<V, U> because though aren’t the same and using one in stead of other will cause compile-time error, but they contain the same information, they encapsulate the same data, and we can always easily convert one to another:

2 * 3 == 3 * 2 like Boolean * Number ~~ Number * Boolean or Pair<String, Number> ~~ Pair<Number, String>

What does this property give us? You could say, this is a mathematical proof, that the order you define members of your data structure in, doesn’t matter.

Associativity: a * (b * c) = (a * b) * c

Lets use our operator once again:

is Pair<U, Pair<V, W>> ~~ Pair<Pair<U, V>, W> true?

again, we could easily define a function that transforms first type into second and vice versa, also they hold the same data and are “equal-ish” (a.k.a isomorphic):

2 * (3 * 4) == (2 * 3) * 4

like Boolean * (String * Boolean) ~~ (Boolean * String) * Boolean

or Pair<String, Pair<Boolean, Number>> ~~ Pair<Pair<String, Boolean>, Number>

Identity: n * 1 = n

So what would be identity (like 1 for numbers) for Product types?

In TypeScript and Flow null and undefined are in void type:

Pair<U, void> ~~ U

FYI: in the functional world it would be called Unit which is a type with only one possible value (like void in TypeScript/Flow is undefined | null which could be counted as one value). The Void type in the functional world is the type with no possible values

So as we see, product types and number multiplication have similar properties: symmetry, associativity and identity.

Now lets look at Sum Types (also called tagged union). Sums of types represent a disjunction, “or,” of those types:

Yep, again, you’ve been using this already!

It can also be written this way in TypeScript/Flow:

It can be read like this:

Errors<U, V> can be either TypeError<U> or SyntaxError<V>

As addition and multiplication, Sum and Product types share properties too. Sum types also have three properties described above, we wont explain them in detail, because they’re almost the same.

Now lets see what happens when we have sum and product types mixed:

e.g. Pair<U, Either<V, W>> lets analyze it for a moment, We have U type and Either<V, W> which means we have: U and ( Left<V> or Right<W> ) and what are the possible outcomes? Pair<U, Left<V>> or Pair<U, Right<W>> this looks like distributive property right? a * (b + c) = a * b + a * c

One last thing, though we went over why this data types are Algebraic, and why they are called Sum and Product, but what is algebra without equations?

Let’s define list class, which is either a Nil (empty list) or Cons the head and tail of the list, it’s a recursive data structure:

We can use it like this:

We can convert List class into a algebraic equation: l(x) = 1 + x * l(x) as you can see, it is a recursive function: l(x) = 1 + x * l(x) = 1 + x * (1 + x * l(x)) = 1 + x + x * l(x) Where 1 is like Nil and x * l(x) is like Cons(x, List)