Vector is a module designed to facilitate mathematical vector operations in the hermitian-style. For simplicity, I model only 3 dimensional vectors but allow the underlying fields to be arbitrary. Complex and Double serve as example fields throughout. The data type ThreeVector has a vector constructor:
V3 x x x and a scalar constructor:
S x. ThreeVector then extends the Functor class with fmap mapping over the components in the obvious way.
import Data.Complex data ThreeVector a = V3 a a a | S a deriving (Eq, Show) instance Functor ThreeVector where fmap f (V3 x y z) = V3 (f x) (f y) (f z) fmap f (S x) = S $ f x
The Comp class introduces conjugation for ThreeVectors. Complex types are conjugated while Double types are left invariant.
class Comp c where conj :: c -> c instance Num a => Comp (Complex a) where conj = conjugate instance Comp Double where conj = id instance Comp a => Comp (ThreeVector a) where conj = fmap conj
conj (2 :+ 3) conj $ V3 (1 :+ 2) (3 :+ (-3)) (0 :+ 1) conj $ V3 1 2 3
2 :+ (-3)
V3 (1 :+ (-2)) (3 :+ 3) (0 :+ (-1))
V3 1.0 2.0 3.0
Now for the heart and soul of any module daring enough to call itself Vector.
The class Vector provides for the four base methods:
- norm, norm
- evaluation, eval
- projections, prs
Simultaneously, I extend Num to include ThreeVector. Extending provides meaning for summing, differencing, multiplying and taking the absolute value wrt ThreeVector. Notice that
abs relies on
norm relies and
abs. This mutual dependency simplifies the code, but requires that both extensions are present at the time of compilation.
instance (Floating a, Num a, Comp a) => Num (ThreeVector a) where (+) (V3 a b c) (V3 x y z) = V3 (a+x) (b+y) (c+z) (-) (V3 a b c) (V3 x y z) = V3 (a-x) (b-y) (c-z) (*) (V3 a b c) (S x) = V3 (a*x) (b*x) (x*x) (*) (S x) (V3 a b c) = V3 (a*x) (b*x) (x*x) abs vect = fmap sqrt (vect vect) class Vector v where (<|>) :: (Num a, Comp a) => v a -> v a -> v a norm :: (Floating a, Comp a) => v a -> v a eval :: Num a => v a -> v a prs :: v a -> [a] instance Vector ThreeVector where (<|>) (V3 a b c) (V3 x y z) = V3 (conj a *x) (conj b *y) (conj c*z) -- Hermitian eval (V3 a b c) = S $ a + b + c prs (V3 a b c) = [a, b, c] norm = eval.abs
Now we can take the Hermitian innerproduct of two complex vectors and return their evaluation.
x = V3 (1 :+ 2) (3 :+ (-3)) (0 :+ 1) y = V3 (3 :+ 2) (1 :+ 2) (5 :+ (-2)) eval $ x <|> y
S (2.0 :+ 0.0)