Enums in OCaml

Enumerated types (enums) are a special case of sum types. An enum is a type that has a fixed number of possible values, each with a distinct name. The target language doesn’t have an enum type as a distinct language feature, but enums are simple to implement using existing language idioms.

Our enum type ServerState has an underlying int type.

type server_state =    
  | StateIdle
  | StateConnected
  | StateError
  | StateRetrying

To map the enum values to their string representations, we can define a function.

let state_name = function
  | StateIdle -> "idle"
  | StateConnected -> "connected"
  | StateError -> "error"
  | StateRetrying -> "retrying"

By implementing a function similar to the fmt.Stringer interface, values of server_state can be printed out or converted to strings.

let string_of_server_state ss = state_name ss

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 = function
  | StateIdle -> StateConnected
  | StateConnected
  | StateRetrying -> StateIdle
  | StateError -> StateError
  | _ -> failwith "unknown state"

Here’s the main function to emulate the state transitions and print the results.

let () =
  let ns = transition StateIdle in
  Printf.printf "%s\n" (string_of_server_state ns);
  let ns2 = transition ns in
  Printf.printf "%s\n" (string_of_server_state ns2)

The transition function emulates a state transition for a server; it takes the existing state and returns a new state.

Suppose we check some predicates here to determine the next state…

$ dune exec ./enums.exe
connected
idle

Now that we understand how to define and use enums in OCaml, let’s learn more about the language.