> | > > class (Eq key, Ord key) => Dictionary dict key dat where
> | > > delete :: key -> dict -> dict
> | ...
> | > the first error:
> | >
> | > Class type variable `dat' does not appear in method signature
> | > delete :: key -> dict -> dict
> | >
> | > Why does ghc expect that I use all of the type variables?
> | > Obviously I only need
> | > the key to remove an entry of a dictionary.
> |
> | You're right. The restriction is excessive. Thanks for pointing
> | this out. Probably we should only require that at least one
> | of the class variables is constrained.
>
> I don't see this. The fact is that, if any of the variables in the
> class header don't appear in the type of a method, then that method
> will always have an ambiguous type. In this case, that would be:
>
> delete :: (Dictionary dict key dat) => key -> dict -> dict
It would not *always* result in ambiguity. For example, consider
instance Dictionary (MyDict dat) Int dat where ...
f :: MyDict dat -> MyDit dat
f d = delete (3::Int) d
Here, the polymorphism in 'dat' doesn't affect which instance
is chosen.
However, on further reflection, I now think:
in any case where ambiguity would not result
the original class declaration should be re-formulated
So, I now think that the existing rule (all class variables
must appear in each class-operation type signature) is probably
the right one, but on stylistic rather than technical grounds.
> I don't see how Simon's suggestion of replacing "all" with "at least one"
> could be made to work in general. Such an approach is however possible
> if you are working with multiple parameter classes where the variables in
> one parameter are determined directly by the parameters in another.
> For example, consider the following class:
>
> class Collection elem col where
> empty :: col
> add :: elem -> col -> col
> del :: elem -> col -> col
> enum :: col -> [elem]
>
> By the argument above, one should expect empty to be rejected as having
> an ambiguous type: Collection elem col => col. However, we could also
> imagine modifying the definition of ambiguity to take account of the fact
> that, in practice, the value of elem would probably be uniquely determined
> by the value of col, and hence the context in which empty is used could
> still provide enough information to allow the overloading to be resolved.
Indeed. Consider
instance Collection a MyColl where
empty = MyEmpty
...
But this would be nearly useless, since we then know nothing
about the type elem.
So, again, nothing seems to be gained by relaxing the restriction
(unlike what I said yesterday).
Simon