Revamping the numeric classes

Bjorn Lisper lisper@it.kth.se
Wed, 7 Feb 2001 13:04:12 +0100 (MET)


Marcin 'Qrczak' Kowalczyk:
>>Me:
>> I'd like to point out the connection between the use of +, - on vector
>> spaces and * for scaling with features in some data parallel languages.  In
>> these languages, writing a + b where a and b are arrays of numerics is
>> interpreted as elementwise addition of a and b. This features generalises to
>> other operations than +, -, other types than numerical ones, and other data
>> structures than arrays.

>This is what I dislike. It's implicit fmap / zipWith / etc. But it only
>works as long as there is only one meaningful way to insert these fmaps.
>When I apply length to a list of lists, is it the length of the whole list
>or a list of lengths of its elements? So there must be explicit ways of
>specifying the amount of fmaps, and one cannot assume that they will be
>always placed automatically. It might be convenient for very specific
>types computation but is not a working general idea.

A natural principle to adopt is that an already typeable expression should
not be transformed. This will for instance resolve the ambiguity in the list
of list example: if l :: [[a]] then length l is already well-typed and
should not be transformed into map length l.

>> Furthermore, some of these languages support "promotion": "lifting" a
>> "scalar"-typed expression, appearing in a context where an array (say)
>> is expected, into an array with suitable dimensions containing copies
>> of the scalar.

>Again, Haskell does not have subtyping. It is not compatible with type
>inference - it can only work in poor languages which require an operation
>to be fully applied where it is used, and either don't have static types
>or require them to be specified explicitly.

I am not so sure about this. Could you exemplify?

Note that you can do some of this overloading already within Haskell's class
system. For instance, one can make lists of Nums into Nums by declaring

instance (Num a) => Num [a] where
x + y = zipWith (+) x y
x * y = zipWith (*) x y
...
fromInteger x = repeat (fromInteger x)
...

Now, if x and y are lists of Nums, then 2*x + y becomes

zipWith (+) (zipWith (*) (repeat fromInteger 2) x) y

>In Haskell trying to implement
>such overloading would be too clumsy and would not work as expected in all
>cases, so better don't go this way.

I should point out that I didn't suggest adding this overloading in Haskell,
I was merely pointing out the connection between vector space syntax/scaling
and features in data parallel languages.

Björn Lisper