InstanceSigs -- rationale for the "must be more polymorphic than"

Simon Peyton Jones simonpj at
Tue Aug 10 19:15:09 UTC 2021

Do you have a concrete example?

I think that the recursive calls will all go via the original class method with its original type - we can't know that it's calling *this* instance till much later.   So I still don't get it.  An example would clear it up.


From: David Feuer <david.feuer at>
Sent: 10 August 2021 12:01
To: Simon Peyton Jones <simonpj at>
Cc: Anthony Clayden <anthony.d.clayden at>; GHC users <glasgow-haskell-users at>
Subject: Re: InstanceSigs -- rationale for the "must be more polymorphic than"

Simon, there are times when a function has to be generalized to be made polymorphic recursive. Perhaps the method takes an argument of type x (not a class parameter), but to call itself, it needs to be able to take types x, T x, T (T x), etc. That additional polymorphism can be introduced in the instance signature. The alternative is to introduce a helper function with extra polymorphism.

On Tue, Aug 10, 2021, 5:15 AM Simon Peyton Jones <simonpj at<mailto:simonpj at>> wrote:

I think you see why the instance sig must be at least as polymorphic than the instantiated signature from the class - because that's what the client is going to expect.  We are building a record of functions, and they must conform to the class signature.

I agree with David's (1) and (2) reasons, but not with (3) or (4), neither of which I quite understand.

There is no compelling reason to make the instance signature more polymorphic - that is, doing so does not increase expressiveness.  But it might make a briefer, more comprehensible type for the reader.  The only alternative would be to insist that the two types are the same, a completely redundant test, but one you might conceivably want on stylistic grounds.

All in all, no big deal.  Instance signature are a convenience, never a necessity.

If you would like to offer a patch for the user manual to explain this better, that would be great.


From: Glasgow-haskell-users <glasgow-haskell-users-bounces at<mailto:glasgow-haskell-users-bounces at>> On Behalf Of David Feuer
Sent: 08 August 2021 09:37
To: Anthony Clayden <anthony.d.clayden at<mailto:anthony.d.clayden at>>
Cc: GHC users <glasgow-haskell-users at<mailto:glasgow-haskell-users at>>
Subject: Re: InstanceSigs -- rationale for the "must be more polymorphic than"

To the best of my knowledge, `InstanceSigs` are never strictly necessary. They can, however, be useful for at least four purposes:

1. To provide a compiler-checked reminder of the type.
2. To bind type variables with `ScopedTypeVariables`.
3. To generalize the type so you can use polymorphic recursion.
4. To enhance parametricitry/polymorphism for internal documentation purposes.

The third reason is probably the main technical one to allow a more general signature, but the fourth is likely helpful too.

On Sun, Aug 8, 2021, 3:04 AM Anthony Clayden <anthony.d.clayden at<mailto:anthony.d.clayden at>> wrote:
I can't help but feel InstanceSigs are either superfluous or upside-down. It's this bit in the User Guide:

> The type signature in the instance declaration must be
> more polymorphic than (or the same as) the one in the class declaration,
> instantiated with the instance type.

Usually if you give a signature, it must be _less_ polymorphic (or the same as) the type inferred from the term:

>    lessPolyPlus :: Integral a => a -> a -> a
>    lessPolyPlus x y = x + y


>    lessPolyPlus (x :: a) y = x + y :: Integral a => a

The examples in the User Guide aren't helping: you could just drop the InstanceSigs, and all is well-typed. (Even the example alleging to use -XScopedTypeVariables in a where sub-decl: you could just put random `xs :: [b]` without scoping `b`.)

Dropping the Sigs altogether works because the type from the class decl, suitably instantiated, is less polymorphic than inferred from the term. IOW the suitably instantiated type restricts what would otherwise be inferred. Situation normal.

I suppose it might be helpful to give an explicit InstanceSig as 'belt and braces' for the instantiated -- possibly because the instantiation is hard to figure out; possibly because you want to use -XScopedTypeVariables within a where-bound sub-decl, as an extra piece of string.

I can see you mustn't make the InstanceSig _less_ polymorphic than the suitably instantiated.

But the docos don't give any example where it's essential to provide an InstanceSig _and_  make it strictly more polymorphic. Here all the sigs and annotations are just superfluous:

>    maxPolyPlus :: Num a => a -> a -> a
>    maxPolyPlus = (+)
>    class C a  where foo :: a -> T a
>    instance Integral a => C a  where
>      foo :: Num a => a -> T a
>      foo (x :: a) = MkT (maxPolyPlus x x :: Num a => a)

Is there a persuasive example (to put in the User Guide)?


Glasgow-haskell-users mailing list
Glasgow-haskell-users at<mailto:Glasgow-haskell-users at><>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Glasgow-haskell-users mailing list