3
votes

Messing around in Haskell getting to know type classes more intimately, but I've hit a bit of a roadblock. For whatever reason I'm not allowed to make an instance of my Vector class. I'm being told that it's an illegal instance declaration because I don't have distinct type variables? What's going on here?

class Vector v where
  vplus :: v -> v -> v
  vmult :: Num a => v -> a -> v

instance Num a => Vector (a, a) where
  (a, b) `vplus` (c, d) = (a + c, b + d)
  (a, b) `vmult` m = (a * m, b * m)
1

1 Answers

6
votes

a in you (a,a) instance will be one arbitrary Num instance. The a in vmult :: Num a => v -> a -> v knows nothing about this, i.e. this may be any other Num instance.

To make the class work you need to either

  • ensure that the number types can be converted into each other. For instance,

    class Vector v where
      vplus :: v -> v -> v
      vmult :: RealFrac a => v -> a -> v
    
    instance RealFrac a => Vector (a, a) where
      (a, b) `vplus` (c, d) = (a + c, b + d)
      (a, b) `vmult` m' = (a * m, b * m)
        where m = realToFrac m'
    
  • make sure the scalar multiplicators are actually the same type as the vector components. This is how the vector-space library does it. For your code, it would take on the form

    {-# LANGUAGE TypeFamilies, FlexibleInstances #-}
    
    class Vector v where
      type Scalar v :: *
      vplus :: v -> v -> v
      vmult :: v -> Scalar v -> v
    
    instance Num a => Vector (a, a) where
      type Scalar (a,a) = a
      (a, b) `vplus` (c, d) = (a + c, b + d)
      (a, b) `vmult` m = (a * m, b * m)