Clean up printing of foralls
Simon and I agreed on several infelicities around the printing of types with foralls. Before cleaning up the code, though, we wanted a specification of what we should do. Here is what we have.
When printing types for users (in GHCi and certain error messages), it is convenient to sometimes suppress
foralls. Given a type
ty to print,
foralls will be suppressed when all of the following are true:
-fprint-explicit-forallsis not in effect.
- The kinds of all bound type variables are Haskell98-style. That is, the kinds consist only of
- No bound type variable is
foralls are all at the top. Exception:
foralls are allowed to be mixed with class constraints, but no
foralls can appear under a proper
- No two quantified type variables are spelled the same.
This decision is made once, while looking at the overall type. Once made, it is not challenged: either all
foralls in a type are printed, or none are. Notice that if any foralls are suppressed, then they are all at the "top" of the type (albeit possibly under class constraints).
Reasons behind the conditions:
- No comment. The only effect of
-fprint-explicit-forallsshould be to turn off the suppression of foralls, and print all foralls unconditionally.
- Currently, we print
forall k (a :: k). ...when there is a bound type variable with a variable kind. But, really, the fact that it's a variable isn't the only way it could be interesting. E.g.
forall (a :: Nat). blah
Requiredtype variables must be supplied; omitting these would be very confusing. E.b. in
T :: forall k -> k -> Typeit would be jolly confusing to omit the
forall k ->part, leaving
T :: k -> Type.
- If a type has nested
foralls, it's best to print all the foralls, including any at the top. Example
f :: forall a. (forall b. b -> b) -> a -> a
Currently we suppress the outer forall, but with the nested forall we are well out of Haskell98-land and it seems better to display them all.
Reason for exception: the type of
return is properly
return :: forall (m :: Type -> Type). Monad m => forall (a :: Type). a -> m a
Note that a
forall is under a class constraint. But we want to suppress the
foralls there, too, to display
return :: Monad m => a -> m a
- Imagine this abuse of our language:
class C a b where meth :: forall a. a -> b
The type of
forall a b. C a b => forall a. a -> b. This is, actually, a well-formed type, where one type variable shadows another. But if we don't print the
foralls, any reader will come to the wrong conclusion about the meaning of the type.
This is a slight tweak to the current rules, meaning more
foralls are printed than previously. Pointedly, this will not happen in Haskell98-style code, so they will not appear for beginners. The current state of affairs is messy, on the other hand, where some
foralls may be suppressed in a type while others are printed, causing more trouble.
While in town, any fix should also address