
Thank you! I agree that what I'm doing isn't useful from an application perspective, but this turned out to be very useful for comprehension. It was the rad :: a b -> b that I was missing. Two type variables-- one for Angle and one for Float. This now compiles just fine: data Angle a = Radians a | Degrees a deriving (Eq, Show) class Angular a where rad :: (Floating b) => a b -> b rad x = pi * (deg x) / 180 deg :: (Floating b) => a b -> b deg x = 180 * (rad x) / pi instance Angular Angle where rad (Radians x) = x deg (Degrees x) = x x :: Angle Float x = Radians (pi / 2) y :: Float y = deg x It just doesn't execute, because of a non-exhaustive pattern for deg. I guess that makes sense-- the default functions are per type, not per value constructor... Changing my instance definition to this: instance Angular Angle where rad (Radians x) = x rad (Degrees x) = pi * x / 180 deg (Radians x) = 180 * x / pi deg (Degrees x) = x resolves the problem. Thanks again for the help. I'm now that much further down the type system learning curve... Cheers-- Greg On Aug 23, 2010, at 8:06 PM, Tobias Brandt wrote:
You don't need a type class, you can just define your functions with pattern matching:
rad :: Angle a -> a rad (Radians x) = x rad (Degrees x) = pi * (deg x) / 180
deg :: Angle a -> a deg (Radians x) = 180 * (rad x) / pi deg (Degrees x) = x
Alternatively, you can define Radians and Degrees as separate types and use a type class:
data Radians a = Radians a data Degrees a = Degrees a
class Angular a where rad :: a b -> b deg :: a b -> b
instance Angular Radians where rad (Radians x) = x deg (Radians x) = 180 * (rad x) / pi
instance Angular Degrees where rad (Degrees x) = pi * (deg x) / 180 deg (Degrees x) = x
This would be extensible, but it this case not really useful.