*A Gentle Introduction to Haskell, Version 98*

back next top

Haskell provides a rich collection of numeric types, based on those of Scheme [7], which in turn are based on Common Lisp [8]. (Those languages, however, are dynamically typed.) The standard types include fixed- and arbitrary-precision integers, ratios (rational numbers) formed from each integer type, and single- and double-precision real and complex floating-point. We outline here the basic characteristics of the numeric type class structure and refer the reader to §6.4 for details.

The numeric type classes (class `Num` and those that lie below it)
account for
many of the standard Haskell classes. We also note that `Num
`is a subclass of `Eq`, but not of `Ord`; this is because the order
predicates do not apply to complex numbers. The subclass `Real
`of `Num`, however, is a subclass of `Ord` as well.

The `Num` class provides several basic operations common to all
numeric types; these include, among others, addition, subtraction,
negation, multiplication, and absolute value:
`
(+), (-), (*) :: (Num a) => a -> a -> a
negate, abs :: (Num a) => a -> a
`[

Note that `Num` does *not* provide a division operator; two
different kinds of division operators are provided in two non-overlapping
subclasses of `Num`:

The class `Integral` provides whole-number division and remainder
operations. The
standard instances of `Integral` are `Integer` (unbounded or
mathematical integers, also known as "bignums") and `Int
`(bounded, machine integers, with a range equivalent to at least
29-bit signed binary). A particular Haskell implementation might
provide other integral types in addition to these. Note that
`Integral` is a subclass of `Real`, rather than of `Num` directly;
this means that there is no attempt to provide Gaussian integers.

All other numeric types fall in the class `Fractional`, which provides
the ordinary division operator `(/)`. The further subclass
`Floating` contains trigonometric, logarithmic, and exponential functions.

The `RealFrac` subclass of `Fractional` and `Real` provides a function
`properFraction`, which decomposes a number into its whole and
fractional parts, and a collection of functions that round to
integral values by differing rules:

properFraction :: (Fractional a, Integral b) => a -> (b,a)

truncate, round,

floor, ceiling: :: (Fractional a, Integral b) => a -> b

`
`The `RealFloat` subclass of `Floating` and `RealFrac` provides
some specialized functions for efficient access to the components
of a floating-point number, the *exponent* and *significand*.
The standard types `Float` and `Double` fall in class `RealFloat`.

Of the standard numeric types, `Int`, `Integer`, `Float`, and `Double
`are primitive. The others are made from these by type constructors.

`Complex` (found in the library `Complex`) is a type constructor that
makes a complex type in class `Floating` from a `RealFloat` type:
`
data (RealFloat a) => Complex a = !a :+ !a deriving (Eq, Text)
`The

conjugate :: (RealFloat a) => Complex a -> Complex a

conjugate (x:+y) = x :+ (-y)

`
`Similarly, the type constructor `Ratio` (found in the `Rational
`library) makes a rational type in class `RealFrac` from an instance of
`Integral`.
(`Rational` is a type synonym for `Ratio Integer`.)
`Ratio`, however, is an abstract type constructor.
Instead of a data constructor like `:+`, rationals use the ``%`' function to
form a ratio from two integers. Instead of pattern matching,
component extraction functions are provided:

(%) :: (Integral a) => a -> a -> Ratio a

numerator, denominator :: (Integral a) => Ratio a -> a

`
`Why the difference? Complex numbers in cartesian form are
unique---there are no nontrivial identities involving `:+`. On the
other hand, ratios are not unique, but have a canonical (reduced) form
that the implementation of the abstract data type must maintain; it is
not necessarily the case, for instance, that `numerator (x%y)` is
equal to `x`, although the real part of `x:+y` is always `x`.

The Standard Prelude and libraries provide several overloaded functions
that serve as explicit coercions:

fromInteger :: (Num a) => Integer -> a

fromRational :: (Fractional a) => Rational -> a

toInteger :: (Integral a) => a -> Integer

toRational :: (RealFrac a) => a -> Rational

fromIntegral :: (Integral a, Num b) => a -> b

fromRealFrac :: (RealFrac a, Fractional b) => a -> b

fromIntegral = fromInteger . toInteger

fromRealFrac = fromRational . toRational

`
`Two of these are implicitly used to provide overloaded numeric literals:
An integer numeral (without a decimal point) is actually equivalent to
an application of `fromInteger` to the value of the numeral as an
`Integer`. Similarly, a floating numeral (with a decimal point) is
regarded as an application of `fromRational` to the value of the
numeral as a `Rational`. Thus, `7` has the type `(Num a) => a`,
and `7.3` has the type `(Fractional a) => a`. This means that we
can use numeric literals in generic numeric functions, for example:
`
halve :: (Fractional a) => a -> a
halve x = x * 0.5
`This rather indirect way of overloading numerals has the additional
advantage that the method of interpreting a numeral as a number
of a given type can be specified in an

fromInteger x = fromInteger x :+ 0

As another example, recall our first definition of `inc` from Section
2:
`
inc :: Integer -> Integer
inc n = n+1
`Ignoring the type signature, the most general type of

Consider the following function definition:
`
rms :: (Floating a) => a -> a -> a
rms x y = sqrt ((x^2 + y^2) * 0.5)
`The exponentiation function

rms x y = sqrt ((x ^ (2::Integer) + y ^ (2::Integer)) * 0.5)

In fact, this kind of overloading ambiguity is not restricted to
numbers:
`
show (read "xyz")
`As what type is the string supposed to be read? This is
more serious than the exponentiation ambiguity, because there, any

Because of the difference between the numeric and general cases of the
overloading ambiguity problem, Haskell provides a solution that is
restricted to numbers: Each module may contain a *default
declaration,* consisting of the keyword `default` followed by a
parenthesized, comma-separated list of numeric monotypes (types with
no variables). When an ambiguous type variable is discovered (such as
`b`, above), if at least one of its classes is numeric and all of its
classes are standard, the default list is consulted, and the first
type from the list that will satisfy the context of the type variable
is used. For example, if the default declaration
`default (Int, Float)` is in effect, the ambiguous exponent above will
be resolved as type `Int`. (See §4.3.4 for more details.)

The "default default" is `(Integer, Double)`, but
`(Integer, Rational, Double)` may also be appropriate. Very cautious
programmers may prefer `default ()`, which provides no defaults.

back next top