F Sharp Programming/Discriminated Unions

Discriminated unions, also called tagged unions, represent a finite, well-defined set of choices. Discriminated unions are often the tool of choice for building up more complicated data structures including linked lists and a wide range of trees.

Creating Discriminated Unions
Discriminated unions are defined using the following syntax:

By convention, union names start with a lowercase character, and union cases are written in PascalCase.

Union Basics: an On/Off switch
Let's say we have a light switch. For most of us, a light switch has two possible states: the light switch can be ON, or it can be OFF. We can use an F# union to model our light switch's state as follows:

We've defined a union called  which has two cases,   and. You can create and use instances of  as follows:

This program has the following types:

It outputs the following: x: On y: Off

Notice that we create an instance of  simply by using the name of its cases; this is because, in a literal sense, the cases of a union are constructors. As you may have guessed, since we use the same syntax for constructing objects as for matching them, we can pattern match on unions in the following way:

The function  has the type.

This program has the following output: x: On y: Off z: On toggle z: Off

Holding Data In Unions: a dimmer switch
The example above is kept deliberately simple. In fact, in many ways, the discriminated union defined above doesn't appear much different from an enum value. However, let's say we wanted to change our light switch model into a model of a dimmer switch, or in other words a light switch that allows users to adjust a lightbulb's power output from 0% to 100% power.

We can modify our union above to accommodate three possible states: On, Off, and an adjustable value between 0 and 100:

We've added a new case,. This case is fundamentally the same as the others, except it takes a single  value in its constructor:

This program outputs: x: On y: Off z: Adjustable 0.25 toggle z: Adjustable 0.75

Creating Trees
Discriminated unions can easily model a wide variety of trees and hierarchical data structures.

For example, let's consider the following binary tree:



Each node of our tree contains exactly two branches, and each branch can either be an integer or another tree. We can represent this tree as follows:

We can create an instance of the tree above using the following code:

This program outputs the following: Node (Leaf 1,Node (Leaf 2,Node (Node (Leaf 4,Leaf 5),Leaf 3)))

Very often, we want to recursively enumerate through all of the nodes in a tree structure. For example, if we wanted to count the total number of Leaf nodes in our tree, we can use: This program outputs: countLeaves simpleTree: 5

Generalizing Unions For All Datatypes
Note that our binary tree above only operates on integers. It is possible to construct unions that are generalized to operate on all possible data types. We can modify the definition of our union to the following:

We can use the union defined above to define a binary tree of any data type:

The functions above have the following types:

This program outputs: firstTree: | |- 1  |   |- 2   |    |     |- 4     |- 5    |- 3 secondTree: | |   |    |- "Red" |- "Orange" |   |- "Yellow" |- "Green" |  |- "Blue" |- "Violet"

Built-in Union Types
F# has several built-in types derived from discriminated unions, some of which have already been introduced in this tutorial. These types include:

Propositional Logic
The ML family of languages, which includes F# and its parent language OCaml, were originally designed for the development of automated theorem provers. Union types allow F# programmers to represent propositional logic remarkably concisely. To keep things simple, let's limit our propositions to four possible cases:

Let's say we had a series of propositions and wanted to determine whether they evaluate to true or false. We can easily write an eval function by recursively enumerating through a propositional statement as follows: The  function has the type.

Here is a full program using the eval function:

This program outputs the following: prop1: true prop2: true prop3: false

Additional Reading
Theorem Proving Examples (OCaml)