[Haskell-cafe] Ambiguous type signature in class declaration
Benjamin Franksen
benjamin.franksen at bessy.de
Thu Apr 28 08:20:08 EDT 2005
On Thursday 28 April 2005 08:42, Bo Herlin wrote:
> Doh, i have another question:
>
> Lets say i do as you wrote:
> > class CRank a b where
> > rank :: a -> b -> Maybe Integer -- Nothing means b is out of
> > range or badly constructed
>
> > unrank :: a -> Integer -> Maybe b -- Nothing means rank is out
> > of range
> >
> > class CCountable a where
> > count :: a -> Maybe Integer -- Nothing means infinity
>
> how do i make a test-class like this:
> > class (CRank a b,CCountable a) => CTestable a where
> > testOne :: a -> Integer -> Bool
> > testUpTo :: a -> Integer -> Bool
> > testOne x r = ((unrank x r) >>= (rank x)) == (Just r)
> > testUpTo x mr = foldr1 (&&) (map (testOne x) [0..m])
> > where
> > m = f (count x)
> > f Nothing = mr
> > f (Just y) = min (y-1) mr
>
> this gives me:
>
> ERROR "./Cafe.lhs":14 - Undefined type variable "b"
It is the same problem as in the familiar 'show . read', that is, the
intermediate type (what is to be read?) is lost. Similarly, in
unrank x r >>= rank x
the compiler cannot infer what the type 'b' in the types of 'rank' and
'unrank' should be. It is essentially the same problem as you had in
the beginning, i.e. ambigous type variables.
Ask yourself: what is this code supposed to do, exactly? Which instance
of 'class CRank a b' should be chosen in
testOne Prime 1
the one for 'CRank Prime Int' or the one for 'CRank Prime Integer'? The
compiler doesn't know that such a combination is not possible, due to
teh superclass restriction.
Note that I wrote in the answer to myself, that the solution that
factorizes 'count' to a superclass has teh disadvantage that it
introduces the same restrictions as the solution using functional
dependencies. Your problem would go away if you used functional
dependencies, like this:
class CRank a b | a -> b where ...
because then the compiler knows your intention, i.e. given a type 'a'
and an instance of 'class CRank a b', then the 'b' is uniquely
determined by this instance.
> If i remove the b like "class (CRank a,CCountable a) => CTestable a
> where" i get:
>
> ERROR "./Cafe.lhs":14 - Wrong number of arguments for class "CRank"
Of course, since you declared class CRank to take two type arguments 'a'
and 'b'.
The general theme here is this: Using classes, i.e. overloading, you
essentially say to the compiler: "Please chose the 'right'
implementation, depending on the argument and/or result types of my
functions!" For this to work, the compiler needs enough information to
make the choice. Type inference can only find out a type, if it has a
term on which to perform the inference. But in 'unrank x r >>= rank x'
there are no longer any terms of type 'b' (the second type argument to
CRank).
HTH,
Ben
More information about the Haskell-Cafe
mailing list