Is it safe to postulate () has one inhabitant?

The () kind has infinitely many inhabitants: the type '() and any stuck or looping types with appropriate kinds. However, I've not been able to find a way to break type safety with the postulate unitsEqual :: (a :: ()) :~: (b :: ()) in GHC 7.10.3 (it was possible using a now-rejected data family in 7.8.3). Is there some way I haven't found yet, or is this safe? If it's *not* safe, is the equivalent postulate using Void instead of () safe? For my purposes, () would be nicer, but it feels riskier.

I believe this is safe, yes.
Saying the kind () has infinitely many types in it is somewhat like saying the type () has infinitely many terms in it, like (), undefined, undefined 1, undefined False, ... With the change to type families in the past few years, it should be impossible to match on any inhabitant of the kind () except the type '(). That makes the postulate you postulate quite sensible.
Richard
On Apr 11, 2016, at 4:07 PM, David Feuer
The () kind has infinitely many inhabitants: the type '() and any stuck or looping types with appropriate kinds. However, I've not been able to find a way to break type safety with the postulate
unitsEqual :: (a :: ()) :~: (b :: ())
in GHC 7.10.3 (it was possible using a now-rejected data family in 7.8.3). Is there some way I haven't found yet, or is this safe? If it's *not* safe, is the equivalent postulate using Void instead of () safe? For my purposes, () would be nicer, but it feels riskier.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

I agree that this should be safe, although it would be nice if someone proved it! Another way to think of it is as a consequence of the eta rule: forall (a :: ()) . a ~ '() There is an existing feature request [1] to add eta conversion to GHC, which should include this. All the best, Adam [1] https://ghc.haskell.org/trac/ghc/ticket/7259 On 12/04/16 01:49, Richard Eisenberg wrote:
I believe this is safe, yes.
Saying the kind () has infinitely many types in it is somewhat like saying the type () has infinitely many terms in it, like (), undefined, undefined 1, undefined False, ... With the change to type families in the past few years, it should be impossible to match on any inhabitant of the kind () except the type '(). That makes the postulate you postulate quite sensible.
Richard
On Apr 11, 2016, at 4:07 PM, David Feuer
mailto:david.feuer@gmail.com> wrote: The () kind has infinitely many inhabitants: the type '() and any stuck or looping types with appropriate kinds. However, I've not been able to find a way to break type safety with the postulate
unitsEqual :: (a :: ()) :~: (b :: ())
in GHC 7.10.3 (it was possible using a now-rejected data family in 7.8.3). Is there some way I haven't found yet, or is this safe? If it's *not* safe, is the equivalent postulate using Void instead of () safe? For my purposes, () would be nicer, but it feels riskier.
-- Adam Gundry, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/

I have heard of this "eta rule" before, but I know nothing about type
theory. What does the rule say?
On Tue, Apr 12, 2016 at 3:41 AM, Adam Gundry
I agree that this should be safe, although it would be nice if someone proved it! Another way to think of it is as a consequence of the eta rule:
forall (a :: ()) . a ~ '()
There is an existing feature request [1] to add eta conversion to GHC, which should include this.
All the best,
Adam
[1] https://ghc.haskell.org/trac/ghc/ticket/7259
On 12/04/16 01:49, Richard Eisenberg wrote:
I believe this is safe, yes.
Saying the kind () has infinitely many types in it is somewhat like saying the type () has infinitely many terms in it, like (), undefined, undefined 1, undefined False, ... With the change to type families in the past few years, it should be impossible to match on any inhabitant of the kind () except the type '(). That makes the postulate you postulate quite sensible.
Richard
On Apr 11, 2016, at 4:07 PM, David Feuer
mailto:david.feuer@gmail.com> wrote: The () kind has infinitely many inhabitants: the type '() and any stuck or looping types with appropriate kinds. However, I've not been able to find a way to break type safety with the postulate
unitsEqual :: (a :: ()) :~: (b :: ())
in GHC 7.10.3 (it was possible using a now-rejected data family in 7.8.3). Is there some way I haven't found yet, or is this safe? If it's *not* safe, is the equivalent postulate using Void instead of () safe? For my purposes, () would be nicer, but it feels riskier.
-- Adam Gundry, Haskell Consultant Well-Typed LLP, http://www.well-typed.com/ _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

On Tue, Apr 12, 2016 at 4:01 PM, David Feuer
I have heard of this "eta rule" before, but I know nothing about type theory. What does the rule say?
In the general use case, "eta rules" are rules that state that any term of a given type must have a specific form defined by the introduction and elimination rules for the type. The standard/original version of eta is for function types: forall (e :: a -> b). e = (\x -> e x) But we can generalize this to other types with a single constructor. For example: forall (e :: ()). e = () forall (e :: (a,b)). e = (fst e, snd e) For any given language/theory, these various eta rules may or may not be true. In Haskell because of decisions about un/liftedness, they prettymuch never hold at the term level. The major counterexamples being _|_ /= (\x -> _|_ x) and _|_ /= (fst _|_, snd _|_). Of course, one could have eta for functions without having it for tuples, and vice versa; there's nothing tying them together. Getting back to the original query, the question is whether these eta rules hold "one level up" where types must be expandable/contractible in particular ways based on the intro/elim rules for their kind. Since we don't have any notion of undefined at the type level, the obvious counterexamples go away; but that still doesn't guarantee they hold. (For example, if we do not allow reduction under binders, then the eta rule for functions won't hold (except perhaps in an up-to-observability sort of way)). -- Live well, ~wren
participants (4)
-
Adam Gundry
-
David Feuer
-
Richard Eisenberg
-
wren romano