Enums in F#

Our enum type ServerState has an underlying int type.

type ServerState =
    | Idle = 0
    | Connected = 1
    | Error = 2
    | Retrying = 3

The possible values for ServerState are defined as constants. Each constant gives a named value corresponding to different server states.

By implementing a custom toString function, values of ServerState can be printed out or converted to strings.

let stateToString state =
    match state with
    | ServerState.Idle -> "idle"
    | ServerState.Connected -> "connected"
    | ServerState.Error -> "error"
    | ServerState.Retrying -> "retrying"

If we have a value of type int, we cannot pass it to transition; the compiler will complain about type mismatch. This provides some degree of compile-time type safety for enums.

let transition state =
    match state with
    | ServerState.Idle -> ServerState.Connected
    | ServerState.Connected | ServerState.Retrying -> ServerState.Idle
    | ServerState.Error -> ServerState.Error
    | _ -> failwithf "unknown state: %A" state

[<EntryPoint>]
let main argv =
    let ns = transition ServerState.Idle
    printfn "%s" (stateToString ns)
    
    let ns2 = transition ns
    printfn "%s" (stateToString ns2)
    0

To run the program, compile it using fsharpc and then execute the built binary.

$ fsharpc enums.fs
$ mono enums.exe
connected
idle

This example demonstrates how to use discriminated unions and pattern matching to create enums in F#, as well as defining and using helper functions to operate on these enums.