Enumerating Union Types in Elm
aka Sum Types, now officially Custom Types
Problem statement
There are times when you want to enumerate a union type. A common example is to render the <option> elements within a <select>. In general each disjoint component of the union may have varying data associated with it.
Custom Types is the official Elm naming and is commonly/formerly known as a (disjoint) Union or Sum types. I'll keep using the Union types naming as it makes sense to me.
Let's start with a simple Union type used effectively like an enum of other languages:
Commonly a solution to having this accessible for enumeration is to manually define a List:
The problem of course with this is that we have two parallel definitions that must be manually kept in sync which is exactly the sort of thing computers, compilers and type systems specifically should solve.
Note that we did add some information rather than merely performing double entry. The carMakes
list defines an ordering whereas the CarMake
type does not. The Elm language and compiler could infer this from the type definition and provide an enumeration mechanism but that's not part of the language.
So let's get on with it and see what's possible. Elm does ensure exhaustive case matching of Union types.
Now if in the above code one of the component types was missed, the compiler would issue an error. This by itself doesn't solve our need. The main problem is that each case is processed independently and we don't have a way of processing every path to produce the full set of values. Even if we fed it our manual list of carMakes
it would only be able to produce the same set we put in replicating any accidental omission.
What we can do is what an accountant would do in such a situation, double-entry and cross check. We can create a successor
definition:
To produce a list from the successor
definition we can start with Nothing
and produce each CarMake
until we end with Nothing
.
All that's left now is to assert carMakes
is the same as carMakes2
.
We can do one better by writing this check once rather than for each Union type.
Last updated