Role
The TypeFamilies language extension allows the programmer to define type-level functions. What distinguishes type functions from non-GADT type constructors is that parameters of type functions can be non-parametric whereas parameters of type constructors are always parametric. This distinction is important to the correctness of the GeneralizedNewTypeDeriving extension. To explicate this distinction, roles are introduced in Haskell.
Nominal Role
Section titled “Nominal Role”Haskell Wiki has an example of a non-parametric parameter of a type function:
type family Inspect xtype instance Inspect Age = Inttype instance Inspect Int = BoolHere x is non-parametric because to determine the outcome of applying Inspect to a type argument, the type function must inspect x.
In this case, the role of x is nominal. We can declare the role explicitly with the RoleAnnotations extension:
type role Inspect nominalRepresentational Role
Section titled “Representational Role”An example of a parametric parameter of a type function:
data List a = Nil | Cons a (List a)
type family DoNotInspect xtype instance DoNotInspect x = List xHere x is parametric because to determine the outcome of applying DoNotInspect to a type argument, the type function do not need to inspect x.
In this case, the role of x is representational. We can declare the role explicitly with the RoleAnnotations extension:
type role DoNotInspect representationalPhantom Role
Section titled “Phantom Role”A phantom type parameter has a phantom role. Phantom roles cannot be declared explicitly.
Remarks
Section titled “Remarks”See also SafeNewtypeDeriving.