Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Vector Typeclass: Function of [a] -> [a] -> a

Alright, I'm trying to wrap my head around typeclasses, and so I'm trying to define a typeclass for geometric vector operations. I managed to get it working for component-wise +,-,*,/; but I'm struggling with the dot product.

class GeomVector a where
  (>+) :: a -> a -> a
  (>-) :: a -> a -> a
  (>*) :: a -> a -> a
  (>/) :: a -> a -> a

  (>.) :: a -> a -> Double

data Vector a = Vec [a]
              deriving Show

instance (Fractional a) => GeomVector (Vector a) where
  (>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v
  (>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v
  (>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v
  (>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v

  (>.) (Vec u) (Vec v) = sum $ u >* v

Obviously my instance definition for (>.) won't work because the result is of type Fractional a, not Double.

But I don't know how to get this behavior from the declaration in the class.

What I'd like to do is:

class GeomVector [a] where
  (>.) :: [a] -> [a] -> a

But this is invalid because [a] is a type and not a type variable.

I wish I could explain this a little better, but I honestly don't understand enough to do so. Hopefully the code will make it a little more obvious what I'm struggling with.

like image 707
Mistodon Avatar asked Dec 04 '12 22:12

Mistodon


1 Answers

Here's one option that could work:

class GeomVector v where
  (>+) :: Num a=> v a -> v a -> v a
  (>-) :: Num a=> v a -> v a -> v a
  (>*) :: Num a=> v a -> v a -> v a
  (>/) :: Fractional a=> v a -> v a -> v a
  (>.) :: Num a=> v a -> v a -> a

data Vector a = Vec { vecList :: [a] }
              deriving Show

instance GeomVector Vector where
  (>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v
  (>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v
  (>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v
  (>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v

  (>.) u v = sum $ vecList (u >* v)

So all your instances of GeomVector will have a kind * -> * like the Monad class. And the types of the methods are not unnecessarily restricted to Fractional types just because you divide somewhere in there.

You might also consider making your class as small as possible (make >. a polymorphic function outside of the class) and whether what you really want is a type class to begin with. But all that depends on what you're designing, and I don't want to presume that I know better than you about that!

like image 54
jberryman Avatar answered Sep 23 '22 08:09

jberryman