[GHC] #11715: Constraint vs *
GHC
ghc-devs at haskell.org
Tue Dec 6 16:40:30 UTC 2016
#11715: Constraint vs *
-------------------------------------+-------------------------------------
Reporter: bgamari | Owner:
Type: bug | Status: new
Priority: high | Milestone: 8.2.1
Component: Compiler (Type | Version: 8.0.1-rc1
checker) |
Resolution: | Keywords: Typeable
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 goldfire):
Simon and I recently hit on a possible solution to this long-standing
infelicity.
1. Add a new constructor of `RuntimeRep` (of levity-polymorphism fame),
`ConstraintRep`. We would then have `type Constraint = TYPE
ConstraintRep`.
Even though values of types of kind `Constraint` have the same runtime
representation as values of types of kind `Type`, it is still OK to have
''more'' distinctions in the type system than are needed at runtime.
With this change, we can have things like `Num a -> a` in Core (where
there is no distinction between `=>` and `->`), and this would be well-
kinded because `->` simply requires that both types have a kind of the
form `TYPE blah` for some `blah`.
GHC currently desugars one-method (and 0-superclass) classes to be
newtypes, not proper datatypes. This is more efficient, of course, than
making a new box to store the dictionary. But it means under this new
scheme that we have a heterogeneous newtype coercion. For example:
{{{#!hs
class C a where
meth :: a -> a
}}}
is desugared into
{{{#!hs
newtype C a = MkCDict { meth :: a -> a }
}}}
which produces a coercion
{{{
axC :: forall (a :: Type). C a ~R# (a -> a)
}}}
Under our new scheme, this coercion would be heterogeneous, because `C a
:: TYPE ConstraintRep` and `(a -> a) :: TYPE LiftedRep`. Of course, GHC
(now) handles heterogeneous equalities just fine, but there is a problem:
GHC can extract a kind equality from a type equality via its `KindCo`
coercion, captured in this typing rule:
{{{
co : (t1 :: k1) ~r# (t2 :: k2)
-----------------------------------------
KindCo co : (k1 :: Type) ~N# (k2 :: Type)
}}}
Note that the premise does not require any particular role on the
coercion, while the conclusion is always nominal. With `KindCo` (and a few
other coercion formers), we could derive a proof of `ConstraintRep ~N#
LiftedRep` from `axC`. This is terrible.
So:
2. Require the coercion in `KindCo` to be nominal.
This makes our equality relation a tiny bit weaker, but I don't think the
lost expressiveness will ever bite. GHC does not currently export a
heterogeneous version of representational equality (although such a thing
exists internally), so users can't every really witness it. And the place
where this is key is in decomposing `AppCo`s, but the roles around
`AppCo`s mean that the coercion relating the arguments is always nominal.
So I think it will work out; building GHC's libraries with this
restriction should be an adequate test.
One remaining problem is that GHC uses newtype axioms for substitutions
in, e.g., newtype unwrapping/normalization. So a heterogeneous axiom is a
bad idea. And I'm not yet sure how to fix this. The normal way to avoid
heterogeneity is just to cast one side. But we can't do this here, because
the coercion we would have to use proves that `Constraint ~N# Type`, which
is precisely what we are trying to avoid! So I'm still a bit stuck on this
point.
Another possible way forward is to do (1), above, and stop encoding one-
element classes as newtypes. This has negative performance implications,
and so that makes me sad.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11715#comment:47>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list