
Udo Stenzel:
Bjorn Lisper wrote:
Here is one way to do it. First, you have to interpret operations on matrices as being elementwise applied. E.g, (*) is interpreted as zipWith (zipWith (*)) rather than matrix multiply
What's this, the principle of greatest surprise at work? Nonono, (*) should be matrix multiplication, fromInteger x should be (x * I) and I should be the identity matrix. Now all we need is an infinitely large I, and that gives:
instance Num a => Num [[a]] where (+) = zipWith (zipWith (+)) (-) = zipWith (zipWith (-)) negate = map (map negate) fromInteger x = fix (((x : repeat 0) :) . map (0:)) m * n = [ [ sum $ zipWith (*) v w | w <- transpose n ] | v <- m ]
There are pros and cons, of course. Using (*) for matrix multiply is well-established in linear algebra. But: - it breaks the symmetry. This particular operator is then overloaded in a different way than all the others, and - your definition of fromInteger will behave strangely with the elementwise extended operations, like (+). 1 + [[1,2],[3,4]] will become [[2,2],[3,5]] rather than [[2,3],[4,5]]. Array languages supporting this kind of overloading invariably have the second form of semantics. Björn Lisper