

--           Dimensional value kind power
data (Num a) => Dim a = Dimensional a String Int
                      | Scalar      a
	              deriving (Show,Eq)


myPlus :: (Num a) => Dim a -> Dim a -> Dim a

myPlus (Scalar x) (Scalar y) = Scalar (x + y)
myPlus d1@(Dimensional v1 k1 p1) d2@(Dimensional v2 k2 p2) =
       if p1 == 0 && p2 == 0
       then Scalar (v1 + v2)
       else if k1 == k2 && p1 == p2
            then Dimensional (v1 + v2) k1 p1
	    else reportError d1 d2
myPlus _ _ = error "scalar + dimensional"


reportError (Dimensional _ k1 p1) (Dimensional _ k2 p2) =
	    error $ "unit mismatch: " ++
	k1 ++ "^" ++ (show p1) ++
	            " vs " ++
	            k2 ++ "^" ++ (show p2)

myMult :: (Num a) => Dim a -> Dim a -> Dim a

myMult (Scalar x) (Scalar y) = Scalar (x * y)
myMult (Scalar x) (Dimensional v k p) = Dimensional (v * x) k p
myMult (Dimensional v k p) (Scalar x) = Dimensional (v * x) k p
myMult d1@(Dimensional v1 k1 p1) d2@(Dimensional v2 k2 p2) =
       if k1 == k2
       then Dimensional (v1 * v2) k1 (p1 + p2)
       else reportError d1 d2

instance (Num a) =>  Num (Dim a) where
	 (+) = myPlus

	 fromInteger x = Scalar (fromInteger x)

	 signum (Scalar x) = Scalar (signum x)
	 signum (Dimensional x k p) = Dimensional (signum x) k p

	 abs (Scalar x) = Scalar (abs x)
	 abs (Dimensional x k p) = Dimensional (abs x) k p

	 (*) = myMult

abc x = x + x
