Original-Via: uk.ac.nsf; Wed, 9 Oct 91 12:11:34 BST
| From: [EMAIL PROTECTED]
| Subject: Multiple implementations of classes
|
| Well, I am ready to scream, so I appeal to the more knowledgable gurus
| on the net. The problem: I am trying to change the Complex
| definition in the prelude as follows: create a general class Complex
| with two instances: CartComp, which is cartesian coordinates, and
| PolComp, which is polar coordinates.
|
| I have (tentatively) defined the general class as follows (to be
| expanded when I insert the polar definitions):
|
| class (Floating a) => Complex a where
| toCart :: a -> a
| realPart,imagPart :: a -> Float
| conjugate :: a -> a
| magnitude,phase :: a -> Float
This would seem to be a case in which we would like multiparameter
classes, i.e.
class (Floating a, RealFloat b) => Complex a b where
toCart :: a -> CartComp b
toPol :: a -> PolComp b
realPart, imagPart :: a -> b
magnitude, phase :: a -> b
conjugate :: a -> a
data (RealFloat a) => CartComp a = a :!+ a
instance (RealFloat a) => Complex (CartComp a) a where
toCart z = z
toPol z = cartToPol z
realPart (x:!+y) = x
imagPart (x:!+y) = y
magnitude z = cartMag z
phase z = cartPhase z
conjugate (x:!+y) = x :!+ (-y)
Unfortunately, Haskell doesn't allow such classes, and likely never
will, because they present some nasty typing problems.
What we can do is to (over-)generalize the class operations above
that involve the real type b to allow _any_ RealFloat type:
class (Floating a) => Complex a where
toCart :: (RealFloat b) => a -> CartComp b
toPol :: (RealFloat b) => a -> PolComp b
realPart, imagPart :: (RealFloat b) => a -> b
magnitude, phase :: (RealFloat b) => a -> b
conjugate :: a -> a
instance (RealFloat a) => Complex (CartComp a) where
toCart = cartCoerce
toPol = cartToPol . cartCoerce
realPart (x:+y) = fromRealFrac x
realPart (x:+y) = fromRealFrac y
magnitude = fromRealFrac . cartMag
phase = fromRealFrac . cartPhase
conjugate = cartCoerce . (\(x:!+y) -> x :!+ (-y))
cartCoerce :: (RealFloat a, RealFloat b) => cartComp a -> CartComp b
cartCoerce (x:!+y) = fromRealFrac x :!+ fromRealFrac y
We can hope that the compiler will be clever enough to elide all the
coercions when we only use complex types with corresponding real types,
e.g., to recognize that the CartComp Float -> CartComp Float instance of
cartCoerce is the identity. Something to watch out for is type ambiguities
or inappropriate defaults, but if, for example, we want to use double
precision everywhere, the "default default" should make the right
thing happen.
This isn't completely satisfactory of course. Maybe someday we'll have
a suitably restricted multiparameter class capability that will allow
something like the first set of declarations above.
On the other hand, maybe somebody knows a better solution in the
existing language?
--Joe