Saturday, March 2, 2024

Algebraic types demystified

In programming, a type is what a variable is allowed to represent.  Typical types are character, integer, and floating point number.  These are the usual atomic types, meaning they hold and represent only one value.  Typical collection types are lists (of one type) and strings (lists of characters).

Functional programmers like to talk about algebraic types.  They wrap these concepts in mystery and superstition, because they originated in mathematics.  They call them "product" and "sum" types.  But really, they're remarkably simple collections of other types.  

Product type = AND collection

A product type is a fixed length, ordered list of various types, where you must fill each element.  A and B and C and D.  It is better known in programming as a tuple.  If you name what each type represents, it is a struct or record.  For those working with an object-oriented language, this is a class.


Sum type = OR collection

A sum type is a set or list of various types, from which you must choose exactly one element to fill.  E or F or G or H.  It is better known as an enum (when referencing elements of a single type) or union (when referencing elements of disparate types).


You can combine these two concepts with each other and the atomic and basic collection types to produce arbitrarily complex data structures.  Some languages even allow types to be recursive, and include themselves as an element.

Contrived example:

type NameOrNumber = union [string, int]    # can be either but not both
var myGirl1, myGirl2: NameOrNumber
myGirl1 = "Jenny"
myGirl2 = 8675309


Overly Contrived Example:

type Lowercase = enum [`a ... `z]    # sum type

type Uppercase = enum [`A ... `Z]    # sum type

type NameFormat =  record       # product type
    initial: Uppercase
    rest: list[Lowercase]

type PersonName = record        # product type
    firstName: NameFormat
    middleInitial: Uppercase
    lastName: NameFormat

type PersonInitials = record        # product type
    firstInitial, middleInitial, lastInitial: Uppercase

type Person = union [PersonName, PersonInitials]    # sum type

var generalName: PersonName        # create a variable
generalName.firstName.initial = `G
generalName.firstName.rest = [`e, `o, `r, `g, `e]
generalName.middleInitial = `S
generalName.lastName.initial = `P
generalName.lastName.rest = [`a, `t, `t, `o, `n]

var nationName: PersonInitials        # create a completely different variable
nationName.firstInitial = `U
nationName.middleInitial = `S
nationName.lastInitial = `A

var name1, name2: Person        # create two variables of the same union type
name1 = generalName               # which are used
name2 = nationName                 # in different ways



No comments:

Post a Comment

I reserve the right to remove egregiously profane or abusive comments, spam, and anything else that really annoys me. Feel free to agree or disagree, but let's keep this reasonably civil.