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 Int
s, 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
.