Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,256
    • Issues 4,256
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 394
    • Merge Requests 394
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #16344

Closed
Open
Opened Feb 20, 2019 by Simon Peyton Jones@simonpjDeveloper

GHC infers over-polymorphic kinds

Consider

data T ka (a::ka) b  = MkT (T Type           Int   Bool)
                           (T (Type -> Type) Maybe Bool)

GHC accepts this even though it uses polymorphic recursion. But it shouldn't -- we simply do not have reliable way to infer most general types in the presence of polymorphic recursion.

In more detail, in getInitialKinds, GHC chooses this (bogus) "monomorphic" kind for T:

   T :: forall (ka :: kappa1) -> ka -> kappa2 -> Type

where kappa1 and kappa1 are unification variables. Then it kind-checks the data constructor declaration, given this mono-kind -- and succeeds!

But this is extremely fragile. At call-sites of T we are going to instantiate T's kind. But what if kappa2 is (somewhere, somehow) late unified wtih ka. Then, when instantiating T's kind with ka := blahwe should get blah -> blha -> Type. So how it instantiates will vary depending on what we konw about kappa2.

No no no. The initial monomorphic kind of T (returned by getInitialKinds, and used when checking the recursive RHSs) should be

   T :: kappa1 -> kappa2 -> kappa3 -> Type

Then indeed this program will be rejected, but so be it. Consider

data T ka (a::ka) b  = MkT (T Type           Int   Bool)
                           (T (Type -> Type) Maybe Bool)

GHC accepts this even though it uses polymorphic recursion. But it shouldn't -- we simply do not have reliable way to infer most general types in the presence of polymorphic recursion.

In more detail, in getInitialKinds, GHC decides this "monomorphic" kind for T:

   T :: forall (ka :: kappa1) -> ka -> kappa2 -> Type

where kappa1 and kappa1 are unification variables. Then it kind-checks the data constructor declaration, given this mono-kind -- and succeeds!

But this is extremely fragile. At call-sites of T we are going to instantiate T's kind. But what if kappa2 is (somewhere, somehow) late unified wtih ka. Then, when instantiating T's kind with ka := blah we might get blah -> blah -> Type or blah -> kappa2 -> Type, depending on whether kappa2 := ka has happened yet.

No no no. The initial monomorphic kind of T (returned by getInitialKinds, and used when checking the recursive RHSs) should be

   T :: kappa1 -> kappa2 -> kappa3 -> Type

Then indeed this program will be rejected, but so be it.

Edited Mar 10, 2019 by Simon Peyton Jones
Assignee
Assign to
8.10.1
Milestone
8.10.1 (Past due)
Assign milestone
Time tracking
None
Due date
None
Reference: ghc/ghc#16344