I thought I would try modeling some numerical integration on vector quantities of different dimensionality, and figured that type classes were the way to go. I needed something to define the difference between two values and to scale it by a multiplier (to get the derivative), as well as being able to take the distance function.
So far I have:
class Integratable a where
difference :: a -> a -> a
scale :: Num b => a -> b -> a
distance :: Num b => a -> a -> b
data Num a => Vector a = Vector1D a | Vector2D a a
instance Num a => Integratable (Vector a) where
difference (Vector1D x1) (Vector1D x2) = Vector1D (x1 - x2)
scale (Vector1D x) m = Vector1D (x * m)
distance (Vector1D x1) (Vector1D x2) = x1 - x2
difference (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
scale (Vector2D x y) m = Vector2D (x * m) (y * m)
distance (Vector2D x1 y1) (Vector2D x2 y2) = sqrt((x1-x2)*(x1-x2)
+ (y1-y2)*(y1-y2))
Unfortunately there are a couple of problems here that I haven't figured out how to resolve. Firstly, the scale
function gives errors. GHC can't tell that m
and x
are compatible since the rigid type restriction Num
is given in the instance in one case, and in the Vector
type in the other case... Is there a way to specify that x
and m
are the same type?
(I realize in fact that even if x
and m
are both Num
, they may not be the same Num
. How can I specify this? If I can't figure it out with Num
, using Double
would be fine, but I'd rather keep it general.)
There's a similar problem with distance
. Attempting to specify that the return type is Num
fails, since it can't tell in the instance definition that a
is going to contain values that are compatible with b
.