
On Wednesday 27 April 2005 19:12, Bo Herlin wrote:
I am trying to make a class like this:
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 count :: a -> Maybe Integer -- Nothing means infinity
but all i get is
ERROR "./Cafe.lhs":8 - Ambiguous type signature in class declaration *** ambiguous type : CRank a b => a -> Maybe Integer *** assigned to : count
The type variable 'b' does not appear on the right side of the '=>' in the type of 'count'. The compiler complains about an 'ambigous type signature', because the type of 'b', and hence of 'count', cannot be determined from its arguments. Thus, if there are instances instance CRank Prime Integer where ... instance CRank Prime Int where ... then these would have different implementations for 'count'. Which one should be chosen if you write count Prime the infinite result for Integers or the (presumably) finite result for Ints? Functional dependencies only help if you never want to declare both of the above instances. If this is not the case (and therefore you don't want to use a fundep 'a -> b'), you can disambiguate the signature by giving it a second (phantom) argument to indicate the type: class CRank a b where ... count :: a -> b -> Maybe Integer -- implementations must not evaluate 2nd argument and call it like this let n = count Prime (undefined::Integer) Admittedly, the extra argument is not very nice and neither is the 'undefined'. Another trick is to split the class: class Countable a where count :: a -> Maybe Integer -- Nothing means infinity class Countable a => CRank a b where rank :: ... ... Ben