[Haskell-cafe] Fwd: Increasing Haskell modularity

Gesh gesh at gesh.uni.cx
Thu Oct 2 18:37:52 UTC 2014


On 10/2/2014 2:50 AM, Richard Eisenberg wrote:
 > Unfortunately, this all breaks apart horribly when thinking about
 > type instances. Global uniqueness, not just coherence, is needed for
 > type instances:
 >
 >> type family F a b
 >> type instance F a b = b
 >>
 >> oops :: F a b -> b
 >> oops = id
 >>
 >> unsafeCoerce :: a -> b
 >> unsafeCoerce = let type instance F a b = a in
 >>                 oops
 >
 > The problem is that a type instance introduces a type equality.
 > Haskell is capable of passing type equality evidence around, so
 > equalities can escape their scope, if the programmer wants to do so.
 > Thus, there can never be a situation where some type (in this case
 > `F a b`) is equal to one thing in one context and an incompatible
 > thing in a different context, anywhere in the same program.
 > I've written my example above with non-associated types, but the
 > same thing can be written with associated types (and more syntactic
 > overhead). I can't currently imagine a type-safe system that did not
 > require global uniqueness for type instances.
Thank you, Richard, for giving a concrete example.

Several things can be said about the above code. First and foremost,
it seems unsafe to allow oops to even typecheck today. Suppose `F` did
not have a catchall instance. Then the type `F a b` is morally
equivalent to `forall a. a`, because we could create any instance we
wished for `F`. Therefore, I would suggest that regardless of my
original proposal being accepted, we only allow open type families in
type signatures where they are either morally equivalent to closed
type families (by having catchall instances) or where they appear as
restrictions on more polymorphic values (such as
`id :: F a b -> F a b`). Associated types would also be permitted if
an instance of their typeclass were in scope.

Second, as hinted above, open type families with catchall instances
are morally equivalent to a closed type families, since no other
instances can be added to them without overlapping with the catchall
instance. Therefore, I also suggest that open type families with
catchall clauses be considered closed.

Finally, this case serves as an excellent example to show that if and
when we add support for local closed type families, we must consider
the local type family distinct from the global one. In particular, one
won't be able to pass instances of the local families to functions
expecting the global family without compromising type safety.

With the proposal from my first point, we outlaw `oops`, even with
associated types, and thereby regain type safety.

Any other problems?

Gesh


More information about the Haskell-Cafe mailing list