F# Snippet - Enums and Discriminated Unions

I was writing some F# code this week and ran into problem. Consider the following code:

 

type Thingey = This | That | SomethingElse

Which looks like an enum. So I assumed that, like things inheriting from System.Enum, an instance of the type had a ToString method which did the right thing. But, alas, when I type it into the F# Interactive Console I get:

 

> (Thingey.That).ToString();;

val it : string = "FSI_0002+Thingey"

 

The reason being is that the type Thingey is actually a Discriminated Union. In F#, to produce an Enumeration type you use the same syntax except you must explicitly provide an integer value for each member. Discriminated Unions can do a lot more than Enums in F#, but there are situations in which to use both.

 

The following snippet shows you how to use Enums and simple Discriminated Union types in F#.

 

#light

open System

// Enum type.

type FruitEnum =

    | Apple = 0

    | Pear = 1

    | Orange = 2

    | Bananna = 3

// Enums have nice built in methods to parse and get their values.

// Note the "typeof<FruitEnum>" syntax to get get the typeof an F# object.

let favoriteFruit = Enum.Parse(typeof<FruitEnum>, "Pear")

let allFruit = Enum.GetValues(typeof<FruitEnum>)

// You can even do some pattern matching...

let isGreen (day : FruitEnum) =

    match day with

    | FruitEnum.Apple | FruitEnum.Pear -> true

    | _ -> false

   

// Consider the following. Leads to undefined results, but

// is valid! This is because any int can be cast to/from an

// enum.

isGreen (Enum.of_int 99999)

// Now consider Discriminated Unions. One of their nice features is that the compiler can enforce

// some nice constraints when pattern matching; such as incomplete or too complete matchings.

type Shape =

    | Circle

    | Square

    | Triangle

// Warning: too few items. Pattern Matching incomplete.

let isRound x =

    match x with

   | Circle -> true

    | Square -> false

    // Warning FS0025: Incomplete pattern matches on this expression.

// Warning: too many items. (Matches more than every item.)

let isSquare x =

    match x with

    | Circle -> false

    | Square -> true

    | Triangle -> false

    | _ -> false

    // Warning FS0026: This rule will never be matched.