Discriminated unions are one of the most useful constructs to model data and work with it in F#.
Discriminated unions sometimes referred to as sum types, unions types, variant record, tagged union or disjoint union. They bring together data that may have a different structure or meaning.
It can be thought of as a data structure used to hold a value that could take on several different, but fixed types. Only one of the types can be in use at any one time, and a case identifier field explicitly indicates the one in use. The type can have several ‘cases’, each of which should be handled correctly when that type is manipulated.
The concept of a discriminated unions comes from mathematics, but can be seen implemented as far back as the 1960s with ALGOL 68. There they are called
You define a discriminated union with a
type keyword followed by a name then the equal sign. Following this comes the case identifiers delimited by the pipe
| symbol. The fist pipe symbol is not mandatory.
In its simplest form a discriminated union can be translated into a .net
enum. To make a .net
enum it is required to use no data elements and assign a value to each of the case identifiers.
Below, Primitive is an example of a more normal discriminated union. It is declared with a case identifiers followed by their type definition.
When creating an instance of a discriminated union it is accessed through a case identifier.
let c = Circle( (3.5, 7.5), 12.5 )
It is also possible to create by prefixing the discriminated union name with the case identifier. This makes sense when you have more than one discriminated union that share the same case identifier name.
let c = Primitive.Circle( (3.5, 7.5), 12.5 )
A discriminated union can be generic and can refer to its self in a recursive manner.
Pattern matching can be used to effectively decompose data held in a discriminated union.
Type augmentation allows methods to be attached to discriminated unions.
Type augmentation can be used on any type, and follows the rules of linear evaluation. This means that the augmented function will only be available to modules and functions that come after its declaration.
Using a discriminated union it is possible to re-create the linked list.
Parsing the list is straight forward with pattern matching, an implementation could be:
Using discriminated unions it is possible to create a Tree data type. It is worth mentioning because it is very simple and powerful.