-- | 'WOE' is an acronym for "Write-Once Enum". This package provides the 'IsoEnum' class to allow for more convenient declaration of arbitrary-index enums. This removes the need for writing boilerplate 'toEnum'/'fromEnum' definitions if you were to implement 'Enum' directly. To expose an 'Enum' interface for your custom enum type (which we'll call 'X'), simply do 'deriving Enum via WOE'. This requires the 'DerivingVia' extension provided by more GHC 8.6.1+.
module Data.WOE(
  WOE(..)
) where

import Data.Tuple
import Data.Maybe

class Eq a => IsoEnum a where
  mapping :: [(Int, a)]

data WOE a = WOE { unwrapWOE :: a }

toEnumSafely :: IsoEnum a => Int -> Maybe a
toEnumSafely n = lookup n mapping

fromEnumSafely :: IsoEnum a => a -> Maybe Int
fromEnumSafely x = lookup x $ swap <$> mapping

instance IsoEnum a => Enum (WOE a) where
  toEnum = maybe (error "Invalid enum index.") WOE . toEnumSafely
  fromEnum = maybe (error "Undefined enum index") id . fromEnumSafely . unwrapWOE