Backward-compatible role annotations

Richard Eisenberg eir at
Mon Mar 31 00:14:55 UTC 2014

I spent some time thinking about what, precisely, can be done here to make folks happier. (See the thread beginning here: And, the answer seemed to all be in the concrete syntax. The only logical alternative (that I could think of) to having roles is to disallow GND, and I don't think anyone is proposing that. And, it is impossible to infer an author's desired roles for a datatype. The heuristics mentioned here all seem far too fragile and hard to predict to become a lasting feature of GHC (in my opinion). What's left? Concrete syntax.

So, I have written and uploaded no-role-annots-1.0, a backward-compatible alternative to role annotations -- no CPP required. It's not as principled as proper role annotations, but it should do the job for most users.

Here are two examples:

1. Datatypes:

> import Language.Haskell.RoleAnnots
> data Map k v =
>   (Nominal k, Representational v) => MkMap [(k,v)]

The constraints (which need be put on only one data constructor, if there are many) will get the built-in role inference mechanism to do what the user requests. In this example, the `Representational v` is actually redundant, but causes no harm. Because these classes have universal instances ("instance Nominal a") and have no methods, they should have no run-time significance. The only downside I can see is that the code above needs -XGADTs or -XExistentialQuantification to work, though it is neither a GADT nor has existentials. (Pattern-matching on such a definition needs no extensions.)

2. Newtypes:

Newtype constructors cannot be constrained, unfortunately. So, we have to resort to Template Haskell:

> import Language.Haskell.RoleAnnots
> roleAnnot [NominalR, RepresentationalR]
>   [d| newtype Map k v = MkMap [(k, v)] |]

This is clearly worse, but I was able to come up with no other solution that worked for newtypes. Note that, in the example, I used the fact that Template Haskell interprets a bare top-level expression as a Template Haskell splice. We could also wrap that line in $( ... ) to be more explicit about the use of TH. Also problematic here is that the code above requires -XRoleAnnotations in GHC 7.8. To get this extension enabled without using CPP, put it in a condition chunk in your .cabal file, like this:

> if impl(ghc >= 7.8)
>   default-extensions: RoleAnnotations

I hope this is helpful to everyone. Please feel free to post issues/pull requests to my github repo at

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the ghc-devs mailing list