Instance declaration of classes with method type constraints
Hi, How do you instantiate from classes with method type constraints, such as this one: class C a where m :: (Num b) => a -> b ?? I have been trying for some time now but everything I have tried fails. In particular, what I want to do is something like this: class Rect a where width :: (Num b) => a -> b height :: (Num b) => a -> b data Num a => PRect a = PRect (a, a) (a, a) deriving (Eq, Show) data IRect = IRect (Int, Int) (Int, Int) deriving (Eq, Show) instance Rect IRect where width ( IRect (x1, _ ) (x2, _ ) ) = abs(x2 - x1) height ( IRect ( _, y1) ( _, y2) ) = abs(y2 - y1) In this case, efforts to intantiate IRect from Rect fails with error messages like: (using GHCI) -----8<----- classtest2.hs:29: Cannot unify the type-signature variable `b' with the type `Int' Expected type: b Inferred type: Int In the expression: x2 - x1 In the first argument of `abs', namely `(x2 - x1)' -----8<----- Again, what should I do to make this work? Also, how is the PRect type to be instantiated? Regards /johan
Hi,
How do you instantiate from classes with method type constraints, such as this one:
class C a where m :: (Num b) => a -> b
This type declaration for 'm' probably doesn't mean what you think it does. I think what you want is "m takes an item of type 'a' and returns an item of a particular type in the Num class, but I'm not going to tell you which one", but what this declaration really means "m takes an item of type 'a' and will return an item of any type you wish, so long as it is in the Num class". In this context 'a' and 'b' are very different kinds of type variables: 'a' is fixed, but 'b' is universally quantified.
I have been trying for some time now but everything I have tried fails.
In particular, what I want to do is something like this:
class Rect a where width :: (Num b) => a -> b height :: (Num b) => a -> b
data Num a => PRect a = PRect (a, a) (a, a) deriving (Eq, Show) data IRect = IRect (Int, Int) (Int, Int) deriving (Eq, Show)
instance Rect IRect where width ( IRect (x1, _ ) (x2, _ ) ) = abs(x2 - x1) height ( IRect ( _, y1) ( _, y2) ) = abs(y2 - y1)
In this case, efforts to intantiate IRect from Rect fails with error messages like: (using GHCI) -----8<----- classtest2.hs:29: Cannot unify the type-signature variable `b' with the type `Int' Expected type: b Inferred type: Int In the expression: x2 - x1 In the first argument of `abs', namely `(x2 - x1)' -----8<-----
The easy fix is to add a call to 'fromIntegral', eg .... = fromIntegral (abs (x2 - x1)) but again, it probably doesn't mean what you want it to mean. Probably what you want is something like this (but requires GHC extensions): {-# OPTIONS -fglasgow-exts #-} class Num b => Rect a b | a -> b where width :: a -> b height :: a -> b instance Rect IRect Int where width ( IRect (x1, _ ) (x2, _ ) ) = abs(x2 - x1) height ( IRect ( _, y1) ( _, y2) ) = abs(y2 - y1)
This type declaration for 'm' probably doesn't mean what you think it does. I think what you want is "m takes an item of type 'a' and returns an item of a particular type in the Num class, but I'm not going to tell you which one", but what this declaration really means "m takes an item of type 'a' and will return an item of any type you wish, so long as it is in the Num class".
In this context 'a' and 'b' are very different kinds of type variables: 'a' is fixed, but 'b' is universally quantified.
Thank you Mr. Dockins for pointing that out, now I understand (I think) why my attempts failed.
[ ... ] {-# OPTIONS -fglasgow-exts #-} class Num b => Rect a b | a -> b where width :: a -> b height :: a -> b
instance Rect IRect Int where width ( IRect (x1, _ ) (x2, _ ) ) = abs(x2 - x1) height ( IRect ( _, y1) ( _, y2) ) = abs(y2 - y1)
This works perfectly! Anyone: However, I haven't been able to make PRect an instance of this class (with extensions). I might not have grasped this yet, but I came to think; if the old class declaration would say that "width" and "height" returns something with unfixed type in the "Num" class, then wouldn't it be possible to make PRect an instance of that class (since PRect has a type parameter)? Something like this: class Rect a where width :: (Num b) => a -> b height :: (Num b) => a -> b data Num a => PRect a = PRect (a, a) (a, a) deriving (Eq, Show) instance Rect PRect a where ... This (as well as my other attemps) fail with a "Kind error: `PRect' is not applied to enough type arguments" - error. Is there a way to do it, or am I lost here? regards /johan
Johan Holmquist <johho590@student.liu.se> writes:
class Num b => Rect a b | a -> b where instance Rect IRect Int where
However, I haven't been able to make PRect an instance of this class (with extensions). I might not have grasped this yet, but I came to think; if the old class declaration would say that "width" and "height" returns something with unfixed type in the "Num" class, then wouldn't it be possible to make PRect an instance of that class (since PRect has a type parameter)?
Something like this:
class Rect a where width :: (Num b) => a -> b height :: (Num b) => a -> b
data Num a => PRect a = PRect (a, a) (a, a) deriving (Eq, Show) instance Rect PRect a where ...
I think this is just a bracketting problem. With the second defn of class Rect above, you probably mean instance Rect (PRect a) where ... whereas if you were intending the earlier defn of class Rect, with two type parameters, then you may mean instance Rect (PRect a) a where ... Regards, Malcolm
Am Donnerstag, 30. Juni 2005 14:07 schrieb Johan Holmquist:
[...]
Anyone:
However, I haven't been able to make PRect an instance of this class (with extensions).
If I understand your problem correctly, you may use the new Rect class (the one which is declared as class Num b => Rect a b | a -> b where ...) and add an instance Num a => Rect (PRect a) a where ...
I might not have grasped this yet, but I came to think; if the old class declaration would say that "width" and "height" returns something with unfixed type in the "Num" class, then wouldn't it be possible to make PRect an instance of that class (since PRect has a type parameter)?
Something like this:
class Rect a where width :: (Num b) => a -> b height :: (Num b) => a -> b
This means that for every type a which is an instance of Rect there is a width and a height of an arbitrary Num type. a and b are independent of each other.
data Num a => PRect a = PRect (a, a) (a, a) deriving (Eq, Show)
instance Rect PRect a where ...
This (as well as my other attemps) fail with a "Kind error: `PRect' is not applied to enough type arguments" - error. Is there a way to do it, or am I lost here?
PRect is of kind * -> *. A type has kind * if an expression can have this type. Examples of kind * types are Int, [Int], PRect Int and PRect a. Kind * -> * means that applying the type to a type of kind * yields a type of kind *. PRect (without any arguments) is an example of a kind * -> * type as well as []. From the type declarations of width an height it is clear that a has to have kind *. So you cannot use PRect for a. You could use PRect c for a but that would mean that width and height would have type Num b => PRect c -> b each, i.e. that c and b would be independent. Another solution would be the following: class Rect r where height :: Num b => r b -> b width :: Num b => r b -> b Because r is applied to b in the type of height and width, r is of kind * -> *. Now you could write instance Rect PRect where ... But you wouldn't be able to do something like instance Rect IRect where ... anymore since IRect is clearly of kind *. With this solution, you would have to have types r of kind * -> * and for every Num instance b, values of type r b would have to have a height and a width.
regards /johan
Best wishes, Wolfgang
Perfect! Problem solved and now I understand about "kinds" of types. instance Rect (PRect a) a where ... works if "Num a" is added to it, like: instance Num a => Rect (PRect a) a where ... (GHC has pretty informative error messages) Thank you for great answers! /johan
participants (4)
-
Johan Holmquist -
Malcolm Wallace -
robert dockins -
Wolfgang Jeltsch