[GHC] #12680: Permit type equality instances in signatures

GHC ghc-devs at haskell.org
Fri Oct 14 01:12:13 UTC 2016


#12680: Permit type equality instances in signatures
-------------------------------------+-------------------------------------
        Reporter:  ezyang            |                Owner:
            Type:  feature request   |               Status:  new
        Priority:  low               |            Milestone:
       Component:  Compiler (Type    |              Version:  8.1
  checker)                           |
      Resolution:                    |             Keywords:  backpack
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):

 This all makes me a bit worried.

 First off, I think the best way to think about all of this is in terms of
 generativity and injectivity. As I read comment:10 and comment:11, I worry
 that these two concepts are being mixed, but they're really quite
 separable. (Below and throughout, we talk only of nominal equality.)

 '''Generativity:''' If `t1` and `t2` are ''generative'', then `t1 a ~ t2
 b` implies `t1 ~ t2`.

 It has been pointed out to me that generativity really describes a set of
 types, any two of which have the property above. That viewpoint may be
 enlightening. In particular, it says that generativity is not really an
 inherent property of a type, but instead exists only by relationship to
 other types.

 '''Injectivity:''' If `t` is injective, then `t a ~ t b` implies that `a ~
 b`.

 Now, to respond to specific points in comment:10 and comment:11:

 > So, that was a really long way of justifying why we can't just search
 replace `type S` with `type family S` and `type S = Int` with `type family
 S = Int`.

 So what ''can'' we say? You say that we can't use type families because
 type family LHSs are not definitionally equal (in FC) to their RHSs.
 (These ''are'' definitionally equal in ''Haskell'', though.) I'm just a
 little lost as the upshot of the first section of comment:10.

 > a type synonym with no type families in it

 I think what you mean here that you want a type synonym that is generative
 and injective. Only things that are generative and injective can appear as
 type patterns (that is, type/data family LHSs and instance heads). I call
 "generative and injective" ''matchable''. The reason that only matchable
 types can appear in type patterns is that matching on anything that's not
 matchable is ill-defined. (Try it.)

 One stumbling block here is that, of course, type synonyms are not
 generative -- a ''synonym'' can't be generative, roughly by definition! So
 what you really mean is that the expansion of the type synonym, after all
 vanilla synonyms are expanded, is matchable. And that no variables are
 lost en route. This is, I imagine, what is done to implement
 `TypeSynonymInstances`. Let's call type synonyms with this property "pre-
 matchable".

 Now we can say: `type T a` in a signature declares a pre-matchable type
 synonym. Any implementing module will need to supply a pre-matchable type
 synonym definition for these pre-matchable type synonyms.

 But I agree that this is a new beast, hitherto unknown.

 > But if H1 and H2 are instantiated in the same way, this equality could
 hold!

 How can this happen? When I see `data`, I think you're declaring a
 matchable type. And matchable types are generative. Do I take that this
 equality between `H1` and `H2` can happen when mixing modules (as in "mix-
 in")?

 If `H1` and `H2` really ''can'' equal, then they would appear to be pre-
 matchable. In this case, how does a `data` definition differ from a `type`
 definition in a signature?

 > Open type families `type family T a` can be implemented by a type
 family, type synonym, data type or newtype.

 So my signature can have `type family T a` and my module `data T a = MkT`?
 That feels very fishy. It seems you are using `type family` as a proxy for
 "type that is not necessarily generative nor injective". Perhaps
 generativity and injectivity properties should just be specified directly.

 > When unifying TyCons in the type inference,

 This should already happen, if you set the results for `isGenerativeTyCon`
 and `isInjectiveTyCon` correctly. (And if the canonicalizer is implemented
 correctly.) You want only a mismatch between generative TyCons do have a
 hard error, and that should be what's implemented.

 --------------------

 In the past, whenever I've been dwelling on these kinds of issues, I have
 found that always reducing the problems to generativity and injectivity to
 be helpful. It might be nice to have a concrete statement of what
 definitions in signatures mean in terms of these properties.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12680#comment:12>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list