A map of Haskell's numeric types
I keep getting lost in the maze of Haskell's numeric types. Here's
the map I drew to help myself out. (I think there might have been something like
this in the original Haskell 1998 report.)
Ovals are typeclasses. Rectangles are types. Black mostly-straight
arrows show instance relationships. Most of the defined functions
have straightforward types like !!\alpha\to\alpha!! or
!!\alpha\to\alpha\to\alpha!! or !!\alpha\to\alpha\to\text{Bool}!!.
The few exceptions are shown by wiggly colored arrows.
Basic plan
After I had meditated for a while on this picture I began to
understand the underlying organization. All numbers support !!=!! and
!!\neq!!. And there are three important properties numbers might
additionally have:
Ord : ordered; supports !!\lt\leqslant\geqslant\gt!! etc.
Fractional : supports division
Enum : supports ‘pred’ and ‘succ’
Integral types are both Ord and Enum , but they are not
Fractional because integers aren't closed under division.
Floating-point and rational types are Ord and Fractional but not
Enum because there's no notion of the ‘next’ or ‘previous’ rational
number.
Complex numbers are numbers but not Ord because they don't admit a
total ordering. That's why Num plus Ord is called Real : it's
‘real’ as constrasted with ‘complex’.
More stuff
That's the basic scheme. There are some less-important elaborations:
Real plus Fractional is called RealFrac .
Fractional numbers can be represented as exact rationals or as
floating point. In the latter case they are instances of
Floating . The Floating types are required to support a large
family of functions like !!\log, \sin,!! and π.
You can construct a Ratio a type for any a ; that's a fraction
whose numerators and denominators are values of type a . If you do this, the
Ratio a that you get is a Fractional , even if a wasn't one. In particular,
Ratio Integer is called Rational and is (of course) Fractional .
Shuff that don't work so good
Complex Int and Complex Rational look like they should exist, but
they don't really. Complex a is only an instance of Num when a
is floating-point. This means you can't even do 3 :: Complex
Int — there's no definition of fromInteger .
You can construct values of type Complex Int , but you can't do
anything with them, not even addition and subtraction. I think the
root of the problem is that Num requires an abs
function, and for complex numbers you need the sqrt function to be
able to compute abs .
Complex Int could in principle support most of the functions
required by Integral (such as div and mod ) but Haskell
forecloses this too because its definition of Integral requires
Real as a prerequisite.
You are only allowed to construct Ratio a if a is integral.
Mathematically this is a bit odd. There is a generic construction,
called the field of quotients, which takes
a ring and turns it into a field, essentially by considering all the
formal fractions !!\frac ab!! (where !!b\ne 0!!), and with !!\frac ab!!
considered equivalent to !!\frac{a'}{b'}!! exactly when !!ab' = a'b!!.
If you do this with the integers, you get the rational numbers; if you
do it with a ring of polynomials, you get a field of rational functions, and
so on. If you do it to a ring that's already a field, it still
works, and the field you get is trivially isomorphic to the original
one. But Haskell doesn't allow it.
I had another couple of pages written about yet more ways in which the
numeric class hierarchy is a mess (the draft title of this article was
"Haskell's numbers are a hot mess") but I'm going to cut the scroll
here and leave the hot mess for another time.
[ Addendum: Updated SVG and PNG to version 1.1. ]
[Other articles in category /prog/haskell]
permanent link
|