Skip to content

Enum

In mathematics, enumerations are sequences of things. Every element in this sequence, except the first, has a predecessor, and every element, except the last, has a successor. Enum is the class of types that represent such enumerations. Making Integral a subclass of Enum is perfectly sensible because integers clearly form such an enumeration in the mathematical sense.

Here's the definition of the Enum type class:

GHCi
>>> :info Enum
type Enum :: * -> Constraint
class Enum a where
  succ :: a -> a
  pred :: a -> a
  toEnum :: Int -> a
  fromEnum :: a -> Int
  enumFrom :: a -> [a]
  enumFromThen :: a -> a -> [a]
  enumFromTo :: a -> a -> [a]
  enumFromThenTo :: a -> a -> a -> [a]
  {-# MINIMAL toEnum, fromEnum #-}
    -- Defined in ‘GHC.Enum’
[More omitted output]

succ and pred are exactly the operations we can use to determine the successor and predecessor of a value of type a in the enumeration of all values of type a. toEnum and fromEnum allow conversion between Enum types and Int. You can think about this Int as the position of the corresponding value of type a in the sequence of all values of type a. The conversion between a and Int is also a hint that under the hood, Enum types are represented as Ints, just as in C. However, in contrast to C, Enum types cannot be used interchangeably with Int. They are different types.

We encountered enumFrom, enumFromThen, enumFromTo, and enumFromThenTo before, when discussing list comprehensions. List comprehensions such as [x..y] or [x..] work not only for integers but for any type a that is an instance of Enum. In particular, the compiler translates the comprehenension [x..y] into the function call enumFromTo x y. The comprehension [x..] gets translated into enumFrom x. The comprehension [x, y..z] gets translated into enumFromThenTo x y z. And the comprehension [x, y..] gets translated into enumFromThen x y.