wiki:GhcKinds/KindInference/Examples

Kind inference examples

This page is intended to collect examples of tricky cases for kind inference. Any proposed algorithm should be applied to each of these cases to see how it would behave.

More discussion is at GhcKinds/KindInference.

Associated types

class C1 (a :: k) where
  type F a

Question: What should the visibilities on F be?

Ryan and Richard think F :: forall k. k -> Type. That is, k is Specified, because we can always order implicit kind variables using the same ordering that appears in the class header (after kind inference).

class C2 (a :: k) (b :: k2) where
  type T a

Proposed: T :: forall k. k -> Type, with no mention of b or k2.

class C3 (a :: k) (b :: k2) hwere
  type T (z :: k3) a

Proposed: T :: forall k k3. k3 -> k -> Type. This puts k before k3, because class variables come before other ones (unless the user explicitly puts them later, as has been done with a). This rule always works because class variables cannot depend on local ones.

class C4 a (b :: a) where
  type T b a

This must be rejected, as b depends on a.

class C5 (a :: k) where
  type T (a :: k2)

Reject: k and k2 are distinct skolems.

class C6 a (b :: a) (c :: Proxy b) where
  type T (x :: Proxy '(a, c))

Proposed: T :: forall (a :: Type) (b :: a) (c :: Proxy b). Proxy '(a, c) -> Type. Note that b is included here as a Specified variable. It could also be an Inferred, if we prefer.

class C7 a (b :: a) (c :: Proxy b) where
  type T a c

Proposed: T :: forall (a :: Type) -> forall (b :: a). Proxy b -> Type. We've inserted b between a and c, but b is Specified, not Required. Other possibilities: make b Inferred, or reject altogether.

Datatypes, dependency, and polymorphic recursion

Assume

data Prox k (a :: k)
data Prox2 k a = MkP2 (Prox k a)

Question: Do we allow k to be dependently quantified, even if this is not lexically apparent from the declaration? This is rejected today.

data S2 k (a :: k) b = MkS (S2 k b a)

Proposed: S2 :: forall k -> k -> k -> Type. Note that a and b are inferred to have the same kind, as that avoid polymorphic recursion.

data S3 k (a :: k) b = MkS (S3 Type b a)

Proposed: reject as polymorphically recursive. Yet the idea in GhcKinds/KindInference#Simonssuggestion accepts this.

data Q2 k a where
  MkQ2 :: Prox k a -> Q2 k a

data Q3 k a where
  MkQ3 :: Q3 k a -> Prox k a -> Q3 k a

data Q4 k a where
  MkQ4 :: Q4 Bool False -> Prox k a -> Q4 k a

data Q5 k a where
  MkQ5 :: Q5 Bool False -> Q5 Nat 3 -> Prox k a -> Q5 k a

Agda accepts all of the above. It puts us to shame!

data Proxy2 a where
  Mk1 :: Proxy2 (a :: k)
  Mk2 :: Proxy2 (b :: j)

This should really be accepted. But it's challenging to arrange this, because a, k, b, and j all scope locally within their constructors. How can the kind of Proxy2 unify with any of them?

data T a where
  Mk :: forall k1 k2 (a :: k1) (b :: k2). T b -> T a

This is polymorphically recursive. Yet hGhcKinds/KindInference#SimonsProposedSolution accepts it. (That's what's implemented in GHC 8.6.) Richard thinks we should reject.

data T2 a where
  Mk :: forall (a :: k). T2 Maybe -> T2 a

This one is rejected, as it should be. So we don't accept all polymorphic recursion (how could we?). But we don't have a good specification for what we do accept and what we don't.

data T3 a b where
  Mk :: T3 b a -> T3 a b

This should be accepted with T3 :: forall k. k -> k -> Type; it's not polymorphically recursive. Yet, it would seem any specification which accepted T would also give T3 the polymorphically recursive kind forall k1 k2. k1 -> k2 -> Type.

data T4 k (a :: k) b = MkT4 (T4 k b a)

Here, we have a dependent kind for T4. Richard thinks this should be accepted. Proposed rule: dependent variables must be fixed an unchanging at all occurrences within a mutually recursive group (otherwise, we have polymorphic recursion). That is, it would be an error to mention, say, T4 k2 anywhere in the body of T4: it must be T4 k.

Generalization

Contrast

class C8 a where
  meth :: Proxy (a :: k)

with

data V1 a where
  MkV1 :: Proxy (a :: k) -> V1 a

Currently (GHC 8.6) we reject C8 while accepting V1. This may be just a bug, but it has to do with the fact that the type of meth isn't quantified over a, but it is over k (lexically).

Dependency ordering

What if we do something simple? Like just use lexical ordering.

data Proxy (a :: k)

Then this example fails, with k after a.

Refinement: consider the RHS of :: before the LHS.

Then this one fails:

data T4 a (b :: k) (x :: SameKind a b)

The k would end up between the a and the b, even though a depends on k.

Also, consider

data T5 a (c :: Proxy b) (d :: Proxy a) (x :: SameKind b d)

Here, b needs to be between a and x somewhere. But where? Currently (GHC 8.6), this is rejected because implicitly declared variables come before explicit ones.

And more

There are many more examples in the testsuite, of course. In particular, see the T14066 tests and the BadTelescope tests.

Comparison to Idris

Idris accepts T4 and T5, so we think Idris use some kind of ScopedSort.

However, Idris also accepts

data T6 :  (a:k) -> (k:Type) -> Type

with type {k : Type} -> (a : k) -> (k2 : Type) -> Type. We think both this acceptance and the inferred type are odd, as we would expect these two ks to be the same k. Then T6 should be rejected because a cannot refer to a variable k that appears after.

Idris would reject

data T7 : (a : k) -> (k:Type) -> (b : k) -> SameKind a b -> Type

with a kind mismatch error between a:k2 and b:k. We agree this should be rejected but it should be rejected with another error: a cannot refer to k.

Difference between Specified and Inferred

The reason we want to accept T4 but reject T6 is because there is a difference between Specified type variable and Inferred type variable. In T4, k is Inferred; thus when we generalize its type, we can put k before a. In contrast, in T6, k is specified, and its order is indicated explicitly by the user, so a is not allowed to refer to it.

Last modified 13 months ago Last modified on Oct 26, 2018 1:50:05 PM