7.13. Type synonyms and hoisting

Type synonmys are like macros at the type level, and GHC is much more liberal about them than Haskell 98. In particular:

GHC does validity checking on types after expanding type synonyms so, for example, this will be rejected:
  type Pr = (# Int, Int #)

  h :: Pr -> Int
  h x = ...
because GHC does not allow unboxed tuples on the left of a function arrow.

However, it is often convenient to use these sort of generalised synonyms at the right hand end of an arrow, thus:
  type Discard a = forall b. a -> b -> a

  g :: Int -> Discard Int
  g x y z = x+y
Simply expanding the type synonym would give
  g :: Int -> (forall b. Int -> b -> Int)
but GHC "hoists" the forall to give the isomorphic type
  g :: forall b. Int -> Int -> b -> Int
In general, the rule is this: to determine the type specified by any explicit user-written type (e.g. in a type signature), GHC expands type synonyms and then repeatedly performs the transformation:
  type1 -> forall a1..an. context2 => type2
==>
  forall a1..an. context2 => type1 -> type2
(In fact, GHC tries to retain as much synonym information as possible for use in error messages, but that is a usability issue.) This rule applies, of course, whether or not the forall comes from a synonym. For example, here is another valid way to write g's type signature:
  g :: Int -> Int -> forall b. b -> Int