0

I am trying to override the + symbol in an effort to learn how to define my own types. I am very new to Haskell, and I cannot seem to get past this error.

Here is my simple new type:

newtype Matrix x = Matrix x
(+):: (Num a, Num b, Num c) => Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]
x + y = Matrix zipWith (\ a b -> zipWith (+) a b) x y

When I try to load this into ghci, I get the error

linear_algebra.hs:9:42:
    Ambiguous occurrence ‘+’
    It could refer to either ‘Main.+’, defined at linear_algebra.hs:9:3
                          or ‘Prelude.+’,
                             imported from ‘Prelude’ at linear_algebra.hs:1:1
                             (and originally defined in ‘GHC.Num’)
Failed, modules loaded: none.

Replacing my last line of code with

x + y = Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y

gives me the error

    Couldn't match expected type ‘([Integer] -> [Integer] -> [Integer])
                                  -> Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]’
                with actual type ‘Matrix
                                    ((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])’
    Relevant bindings include
      y :: Matrix [[b]] (bound at linear_algebra.hs:9:5)
      x :: Matrix [[a]] (bound at linear_algebra.hs:9:1)
      (+) :: Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]
        (bound at linear_algebra.hs:9:1)
    The function ‘Matrix’ is applied to four arguments,
    but its type ‘((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])
                  -> Matrix ((a0 -> b0 -> c0) -> [a0] -> [b0] -> [c0])’
    has only one
    In the expression:
      Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y
    In an equation for ‘+’:
        x + y = Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y
Failed, modules loaded: none.

Can you please help me understand what the error is? I would really appreciate it. Thanks!

Hunter Vallejos
  • 131
  • 1
  • 5
  • 4
    You can not *override* in Haskell, only implement a type class, like the `Num` typeclass: http://learnyouahaskell.com/making-our-own-types-and-typeclasses#typeclasses-102 – Willem Van Onsem Oct 02 '18 at 20:18
  • And frankly, making `Matrix` an instance of `Num` doesn't make sense. (You *could*, if you really wanted to...but what's the sign of a matrix? What matrix should `fromInteger 3` evaluate to?) – cHao Oct 02 '18 at 20:36
  • Be sure to read error messages carefully "...The function ‘Matrix’ is applied to four arguments but it's type has only one, in the expression `Matrix zipWith (\ a b -> zipWith (Prelude.+) a b) x y`..." . You are missing parens – jberryman Oct 02 '18 at 20:38

1 Answers1

6

First of all, the type

(+) :: (Num a, Num b, Num c) => Matrix [[a]] -> Matrix [[b]] -> Matrix [[c]]

is too much general. It states that you can sum any numeric matrix with any other numeric matrix, even if the element types are different, to produce a matrix of a third numeric type (potentially distinct from the first two). That is, in particular a matrix of floats can be summed to a matrix of doubles to produce a matrix of ints.

You want instead

(+) :: Num a => Matrix [[a]] -> Matrix [[a]] -> Matrix [[a]]

I would recommend to move the "list of list" type inside the newtype

newtype Matrix a = Matrix [[a]]

reflecting that the list of lists implements the Matrix concept. That gives the type signature

(+) :: Num a => Matrix a -> Matrix a -> Matrix a

To "override" (+): there's no overriding/overloading in Haskell. The closest options are:

  1. define a module-local function (+). This will clash with Prelude.(+), so that every + will now need to be qualified to remove the ambiguity. We can not write x + y, but we need x Prelude.+ y or x MyModuleName.+ y.

  2. implement a Num instance for Matrix a. This is not a great idea since a matrix is not exactly a number, but we can try anyway.

    instance Num a => Num (Matrix a) where
       Matrix xs + Matrix ys = Matrix (zipWith (zipWith (+)) xs ys)
       -- other Num operators here
      (*) = error "not implemented" -- We can't match dimension
      negate (Matrix xs) = Matrix (map (map negate) xs)
      abs = error "not implemented"
      signum = error "not implemented"
      fromInteger = error "not implemented"
    

    This is very similar to your code, which lacks some parentheses. Not all the other methods can be implemented in a completely meaningful way, since Num is for numbers, not matrices.

  3. use a different operator, e.g. (^+) or whatever

dfeuer
  • 48,079
  • 5
  • 63
  • 167
chi
  • 111,837
  • 3
  • 133
  • 218