Enums in Lisp

Our enum type ServerState has an underlying int type.

(defpackage :server-state
  (:use :common-lisp)
  (:export :server-state :state-idle :state-connected :state-error :state-retrying :state-name :state-name-str :transition))

(in-package :server-state)

(defconstant +state-idle+ 0)
(defconstant +state-connected+ 1)
(defconstant +state-error+ 2)
(defconstant +state-retrying+ 3)

(defvar *state-name* 
  (make-hash-table))

(setf (gethash +state-idle+ *state-name*) "idle")
(setf (gethash +state-connected+ *state-name*) "connected")
(setf (gethash +state-error+ *state-name*) "error")
(setf (gethash +state-retrying+ *state-name*) "retrying")

(defun state-name-str (state)
  (gethash state *state-name*))

(defun transition (s)
  (case s
    (+state-idle+ +state-connected+)
    ((+state-connected+ +state-retrying+) +state-idle+)
    (+state-error+ +state-error+)
    (t (error "unknown state: ~a" s))))

(defun main ()
  (let ((ns (transition +state-idle+)))
    (format t "~a~%" (state-name-str ns))
    (let ((ns2 (transition ns)))
      (format t "~a~%" (state-name-str ns2)))))

(main)

To run the code, evaluate it using a Common Lisp implementation like SBCL, CLISP, or another compliant interpreter.

$ sbcl --script enums.lisp
connected
idle

The transition function emulates a state transition for a server; it takes the existing state and returns a new state based on input. Each state is represented by an integer constant, and human-readable string names are stored in a hash table. The state-name-str function converts state values to their string representations.