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:
>>> :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.