A sample revised prelude for numeric classes

Dylan Thurston dpt@math.harvard.edu
Tue, 13 Feb 2001 14:01:25 -0500


On Mon, Feb 12, 2001 at 12:26:35AM +0000, Marcin 'Qrczak' Kowalczyk wrote:
> I must say I like it. It has a good balance between generality and
> usefulness / convenience.
> 
> Modulo a few details, see below.
> 
> > > class (Num a, Additive b) => Powerful a b where
> > >     (^) :: a -> b -> a
> > > instance (Num a) => Powerful a (Positive Integer) where
> > >     a ^ 0 = one
> > >     a ^ n = reduceRepeated (*) a n
> > > instance (Fractional a) => Powerful a Integer where
> > >     a ^ n | n < 0 = recip (a ^ (negate n))
> > >     a ^ n         = a ^ (positive n)
> 
> I don't like the fact that there is no Powerful Integer Integer.
> Since the definition on negative exponents really depends on the first
> type but can be polymorphic wrt. any Integral exponent, I would make
> other instances instead:
> 
> instance RealIntegral b          => Powerful Int       b
> instance RealIntegral b          => Powerful Integer   b
> instance (Num a, RealIntegral b) => Powerful (Ratio a) b
> instance                            Powerful Float     Int
> instance                            Powerful Float     Integer
> instance                            Powerful Float     Float
> instance                            Powerful Double    Int
> instance                            Powerful Double    Integer
> instance                            Powerful Double    Double

OK, I'm slow.  I finally understand your point here.  I might leave
off a few cases, and simplify this to

instance Powerful Int Int
instance Powerful Integer Integer
instance (Num a, SmallIntegral b) => Powerful (Ratio a) b
instance Powerful Float Float
instance Powerful Double Double
instance Powerful Complex Complex

(where "SmallIntegral" is a class that contains toInteger; "small" in
the sense that it fits inside an Integer.)  All of these call one of 3
functions:
  postivePow :: (Num a, SmallIntegral b) => a -> b -> a
  integerPow :: (Fractional a, SmallIntegral b) => a -> b -> a
  analyticPow :: (Floating a) => a -> a -> a
(These 3 functions might be in a separate module from the Prelude.)
Consequences: you cannot, e.g., raise a Double to an Integer power
without an explicit conversion or calling a different function (or
declaring your own instance).  Is this acceptable?  I think it might
be: after all, you can't multiply a Double by an Integer either...
You then have one instance declaration per type, just as for the other
classes.

Opinions?  I'm still not very happy.

Best,
	Dylan Thurston