Personal tools

Generic number type

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
m (Generic numeric type moved to Generic number type)
(link to Converting numbers)
Line 28: Line 28:
 
=== average ===
 
=== average ===
   
You may find it cumbersome to write
+
You may find it cumbersome to manually [[Converting numbers|convert]] integers to fractional number types like in
 
<haskell>
 
<haskell>
 
average :: Fractional a => [a] -> a
 
average :: Fractional a => [a] -> a

Revision as of 12:20, 20 June 2007

Contents

1 Problem

Question:

Can I have a generic numeric data type in Haskell which covers
Integer
,
Rational
,
Double
and so on, like it is done in scripting languages like Perl and MatLab?

Answer: In principle you can define a type like

data GenericNumber =
    Integer Integer
  | Rational Rational
  | Double Double
and define appropriate instances for
Num
class et. al.

However you will find that it is difficult to implement these methods in a way that is appropriate for each use case. There is simply no type that can emulate the others. Floating point numbers are imprecise - a/b*b=a does not hold in general. Rationals are precise but pi and sqrt 2 are not rational.

That is, when using
GenericNumber
s you will encounter exactly the problems

that all scripting language users have encountered so far (or ignored :-).


2 Solutions

It is strongly advised to carefully check whether a GenericNumber is indeed useful for your application. So let's revisit some examples and their idiomatic solutions in plain Haskell 98.

2.1 average

You may find it cumbersome to manually convert integers to fractional number types like in

average :: Fractional a => [a] -> a
average xs = sum xs / fromIntegral (length xs)

and you may prefer

average :: [GenericNumber] -> GenericNumber
average xs = sum xs / genericNumberLength xs
with an appropriate implementation of
genericNumberLength
. However, there is already
Data.List.genericLength
and you can write
average :: Fractional a => [a] -> a
average xs = sum xs / genericlength xs

2.2 ratios

You find it easy to write

1 / 3 :: Rational

but uncomfortable that

1 / floor pi :: Rational

does not work.

The first example works, because the numeric literals
1
and
3
are interpreted as rationals itself. The second example fails, because
floor
always returns an
Integral
number type, where
Rational
is not an instance. You should use
%
instead. This constructs a fraction out of two integers:
1 % 3 :: Rational
1 % floor pi :: Rational


3 See also