no-role-annots-1.0: Role annotations without -XRoleAnnotations

Portabilitynon-portable
Stabilityexperimental
MaintainerRichard Eisenberg (eir@cis.upenn.edu)
Safe HaskellTrustworthy

Language.Haskell.RoleAnnots

Description

This module provides three class constraints that can be used to make roles stricter in your datatypes. Here is a typical use case:

 -- Use an association list as a map:
 data Map k v =
   (Nominal k, Representational v) => MkMap [(k,v)]

With a declaration such as this, GHC will assign correct roles to k and v. In versions of GHC before roles, these constraints have no effect. The constraints need be put on only one data constructor, though there is no harm in duplicating them.

Note that these constraints can only make roles stricter, such as a change from representational to nominal. Indeed, going the other way would not be type-safe! Thus, there is no guarantee that a parameter has the role given -- the guarantee is only that a parameter as at least the role given. (Thus, Phantom is always redundant and is included only for completeness.)

Unfortunately, the trick above does not work for newtypes, which cannot accept constraints. The only solution there is Template Haskell. Use the function roleAnnot.

To check that the roles are what you would expect, see module Language.Haskell.RoleAnnots.Check.

Synopsis

Documentation

class Nominal a Source

Mark a type parameter as having a nominal role

Instances

Nominal k a 

class Representational a Source

Mark a type parameter as having a representational role

Instances

class Phantom a Source

Mark a type parameter as having a phantom role. (This is always redundant.)

Instances

Phantom k a 

roleAnnot :: [Role] -> Q [Dec] -> Q [Dec]Source

A backward-compatible (almost) role annotation. To use, write code like this:

 roleAnnot [NominalR, RepresentationalR]
   [d| newtype MyMap k v = MkMyMap [(k,v)] |]

You will, of course, need -XTemplateHaskell.

The almost above refers to the fact that this will require the -XRoleAnnotations extension. How to avoid using CPP in this case? Put the extension in your .cabal file, like this:

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

(Cabal files need no endif -- they use indentation to detect the body of the conditional.)

You can check this out in action in the cabal file for no-role-annots (in the test-suite section).

data Role Source

This declaration mirrors the declaration within Template Haskell, for use in earlier versions of GHC.