A sample revised prelude for numeric classes

William Lee Irwin III wli@holomorphy.com
Sun, 11 Feb 2001 21:57:03 -0800

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> Including laws was discussed very early in the development of the
> language, but was rejected. IIRC Miranda had them. The argument against
> laws was that their presence might mislead users into the assumption
> that they did hold, yet if they were not enforcable then they might not
> hold and that could have serious consequences. Also, some laws do not
> hold in domains with bottom, e.g. a + (negate a) === 0 is only true if a
> is not bottom. 

I actually think it would be useful to have them and optionally
dynamically enforce them, or at least whichever ones are computable, as
a compile-time option. This would be _extremely_ useful for debugging
purposes, and I, at the very least, would use it. I think Eiffel does
something like this, can anyone else comment?

This, of course, is a language extension, and so probably belongs in
a different discussion from the rest of all this.

Dylan Thurston wrote:
>> class (Additive a) => Num a where
>>     (*)         :: a -> a -> a
>>     one         :: a
>>     fromInteger :: Integer -> a
>>       -- Minimal definition: (*), one
>>     fromInteger 0         = zero
>>     fromInteger n | n < 0 = negate (fromInteger (-n))
>>     fromInteger n | n > 0 = reduceRepeat (+) one n

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> This definition requires both Eq and Ord!!!

Only on Integer, not on a.

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> As does this one:

Dylan Thurston wrote:
>> 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 should note that both of these definitions which require Eq and
Ord only require it on Integer.

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> and several others further down. 

I'm not sure which ones you hit on, though I'm sure we'd all be more
than happy to counter-comment on them or repair the inadequacies.

Dylan Thurston wrote:
>> (4) In some cases, the hierarchy is not finely-grained enough:
>>     operations that are often defined independently are lumped
>>     together.  For instance, in a financial application one might want
>>     a type "Dollar", or in a graphics application one might want a
>>     type "Vector".  It is reasonable to add two Vectors or Dollars,
>>     but not, in general, reasonable to multiply them.  But the
>>     programmer is currently forced to define a method for (*) when she
>>     defines a method for (+).

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> Why do you stop at allowing addition on Dollars and not include
> multiplication by a scalar? Division is also readily defined on Dollar
> values, with a scalar result, but this, too, is not available in the
> proposal. 

I can comment a little on this, though I can't speak for someone else's
design decisions. In general, the results of division and multiplication
for units have a different result type than those of the arguments. This
makes defining them by type class overloading either require existential
wrappers or makes them otherwise difficult or impossible to define.

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> Having Units as types, with the idea of preventing adding Apples to
> Oranges, or Dollars to Roubles, is a venerable idea, but is not in
> widespread use in actual programming languages. Why not?

I'm probably even less qualified to comment on this, but I'll conjecture
that the typing disciplines of most languages make it impractical. I
suspect it could be possible in Haskell.

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> Vectors, too, can be multiplied, producing both scalar- and
> vector-products.

Exterior and inner products both encounter much the same troubles as
defining arithmetic on types with units attached, with the additional
complication that statically typing dimensionality is nontrivial.

On Mon, Feb 12, 2001 at 05:24:37PM +1300, Brian Boutel wrote:
> It seems that you are content with going as far as the proposal permits,
> though you cannot define, even within the revised Class system, all the
> common and useful operations on these types. This is the same situation
> as with Haskell as it stands. The question is whether the (IMHO)
> marginal increase in flexibility is worth the cost.
> This is not an argument for not separating Additive from Num, but it
> does weaken the argument for doing it.

I'm not convinced of this, though I _am_ convinced that a general
framework for units would probably be useful to have in either a
standard or add-on library distributed with Haskell, or perhaps to
attempt to address units even within the standard Prelude if it's
simple enough. Are you up to perhaps taking a stab at this? Perhaps
if you tried it within the framework Thurston has laid out, some of
the inadequacies could be revealed.