Note [Required, Specified, and Inferred for types]
Each forall'd type variable in a type or kind is one of
* Required: an argument must be provided at every call site
* Specified: the argument can be inferred at call sites, but
may be instantiated with visible type/kind application
* Inferred: the argument must be inferred at call sites; it
is unavailable for use with visible type/kind application.
Why have Inferred at all? Because we just can't make user-facing
promises about the ordering of some variables. These might swizzle
around even between minor released. By forbidding visible type
application, we ensure users aren't caught unawares.
Go read Note [VarBndrs, ForAllTyBinders, TyConBinders, and visibility] in GHC.Core.TyCo.Rep.
The question for this Note is this:
given a TyClDecl, how are its quantified type variables classified?
Much of the debate is memorialized in #15743.
Here is our design choice. When inferring the ordering of variables
for a TyCl declaration (that is, for those variables that the user
has not specified the order with an explicit `forall`), we use the
following order:
1. Inferred variables
2. Specified variables; in the left-to-right order in which
the user wrote them, modified by scopedSort (see below)
to put them in dependency order.
3. Required variables before a top-level ::
4. All variables after a top-level ::
If this ordering does not make a valid telescope, we reject the definition.
Example:
data SameKind :: k -> k -> *
data Bad a (c :: Proxy b) (d :: Proxy a) (x :: SameKind b d)
For Bad:
- a, c, d, x are Required; they are explicitly listed by the user
as the positional arguments of Bad
- b is Specified; it appears explicitly in a kind signature
- k, the kind of a, is Inferred; it is not mentioned explicitly at all
Putting variables in the order Inferred, Specified, Required
gives us this telescope:
Inferred: k
Specified: b : Proxy a
Required : (a : k) (c : Proxy b) (d : Proxy a) (x : SameKind b d)
But this order is ill-scoped, because b's kind mentions a, which occurs
after b in the telescope. So we reject Bad.
Associated types
~~~~~~~~~~~~~~~~
For associated types everything above is determined by the
associated-type declaration alone, ignoring the class header.
Here is an example (#15592)
class C (a :: k) b where
type F (x :: b a)
In the kind of C, 'k' is Specified. But what about F?
In the kind of F,
* Should k be Inferred or Specified? It's Specified for C,
but not mentioned in F's declaration.
* In which order should the Specified variables a and b occur?
It's clearly 'a' then 'b' in C's declaration, but the L-R ordering
in F's declaration is 'b' then 'a'.
In both cases we make the choice by looking at F's declaration alone,
so it gets the kind
F :: forall {k}. forall b a. b a -> Type
How it works
~~~~~~~~~~~~
These design choices are implemented by two completely different code
paths for
* Declarations with a standalone kind signature or a complete user-specified
kind signature (CUSK). Handled by the kcCheckDeclHeader.
* Declarations without a kind signature (standalone or CUSK) are handled by
kcInferDeclHeader; see Note [Inferring kinds for type declarations].
Note that neither code path worries about point (4) above, as this
is nicely handled by not mangling the res_kind. (Mangling res_kinds is done
*after* all this stuff, in tcDataDefn's call to maybeEtaExpandAlgTyCon.)
We can tell Inferred apart from Specified by looking at the scoped
tyvars; Specified are always included there.
Design alternatives
~~~~~~~~~~~~~~~~~~~
* For associated types we considered putting the class variables
before the local variables, in a nod to the treatment for class
methods. But it got too complicated; see #15592, comment:21ff.
* We rigidly require the ordering above, even though we could be much more
permissive. Relevant musings are at
https://gitlab.haskell.org/ghc/ghc/issues/15743#note_161623
The bottom line conclusion is that, if the user wants a different ordering,
then can specify it themselves, and it is better to be predictable and dumb
than clever and capricious.
I (Richard) conjecture we could be fully permissive, allowing all classes
of variables to intermix. We would have to augment ScopedSort to refuse to
reorder Required variables (or check that it wouldn't have). But this would
allow more programs. See #15743 for examples. Interestingly, Idris seems
to allow this intermixing. The intermixing would be fully specified, in that
we can be sure that inference wouldn't change between versions. However,
would users be able to predict it? That I cannot answer.
Test cases (and tickets) relevant to these design decisions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
T15591*
T15592*
T15743* References 1
- Inferring kinds for type declarations GHC.Tc.TyCl
Referenced by 8
- GHC.Tc.Gen.HsType call site ×3
- GHC.Tc.TyCl call site
- Inferring kinds for type declarations GHC.Tc.TyCl
- Bad TyCon telescopes GHC.Tc.Validity
- VarBndrs, ForAllTyBinders, TyConBinders, and visibility GHC.Types.Var
- ExplicitTuple Language.Haskell.Syntax.Expr