[GHC] #16148: Better type inference for Constraint vs Type
GHC
ghc-devs at haskell.org
Tue Jan 8 10:57:38 UTC 2019
#16148: Better type inference for Constraint vs Type
-------------------------------------+-------------------------------------
Reporter: simonpj | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.6.3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by simonpj):
Richard responds: This has come up before, of course. I've always had an
affinity for choice (A). It's easy to describe, even to users, and I think
it will lead to nice error messages (which can special-case printing
unsolved TC constraints). I don't think it would take all that much code.
(C) doesn't actually work, tempting though it may be. Consider (
{{{
f :: forall (r :: RuntimeRep) (a :: TYPE r). a -> ()
}}}
Don't worry about levity-polymorphism restrictions in binding positions,
as that's not the issue here. The question is: does f take 1 visible
argument or 0? The answer depends on the choice of r (under plan C),
because r might be LiftedRep C. So have no way of reliably instantiating
f's type at an occurrence and are thus dead in the water.
Plan D:
{{{
data TC = T | C
TYPE :: RuntimeRep -> TC -> Type
}}}
That is, make the T/C distinction totally orthogonal to representation,
and simply disallow any quantification over a type whose kind has a
variable in the TC position. This has the nice side effect of allowing
unlifted constraints (e.g., an unboxed implicit parameter or a strict
dictionary). But it has the significant drawback of polluting the type of
`(->)`, which would now be
{{{
(->) :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) (tc1 :: TC) (tc2 ::
TC).
TYPE r1 tc1 -> TYPE r2 tc2 -> TYPE LiftedRep tc2
}}}
Indeed, we have considered this route before, [https://github.com/ghc-
proposals/ghc-
proposals/blob/0506dd68fefa26f56dd8e377d4c9d34bf241252f/proposals/0000
-constraint-vs-type.rst here].
The main drawback I see from that abandoned approach in the proposal is
that it banned newtype-classes. I don't think we have a satisfactory way
(yet) of eliminating newtype-classes while keeping, e.g., reflection
working. (This matters: singletons uses the reflection trick to change
exponentially-slow processes to linear ones.)
Summing up, I see two ways forward:
- Simon's (A)
- (D) above, including banning newtype-classes and coming up with a new
way for the reflection trick to work.
Simon's (B) would work, but it seems strictly inferior to (A), simply
because a new TyVar flavor is a more obscure approach to getting the
behavior we would see in (A), whereas (A) uses an abstraction (a class-
like constraint) that everyone knows and loves.
Between these two approaches, (A) is at least an order of magnitude
easier. So I vote for that. :) I do believe, though, that we'll have to do
(D) eventually, though.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/16148#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list