GHC 8.0.x Migration Guide

This guide summarises the changes you may need to make to your code to migrate from GHC 7.10 to GHC 8.0. This guide complements the GHC 8.0.x release notes which should be consulted as well.

Compiler changes

Impredicative types brokenness

Note that the -XImpredicativeTypes extension, which has been known to be broken for many years, is even more broken than usual in this release (see #11319, #11675, and others). During pre-release testing we encountered a number of projects that broke with confusing type errors due to (often unnecessary) use of -XImpredicativeTypes. Users of -XImpredicativeTypes do so at their own risk!

In many cases, this can be fixed by rewriting a = f . g to a x = f (g x).

Requirement for impredicative types

In previous versions of GHC, it was possible to hide an impredicative type behind a type synonym, because GHC did not always expand type synonyms when checking for impredicativity. GHC 8 is stricter in this regard, so code that compiled with -XRankNTypes may now require -XImpredicativeTypes (bearing in mind its potential brokenness) or may need to be rewritten to avoid impredicativity. See #10194, this thread, this thread and this thread.

More conservative use of superclass constraints while solving

The compiler is now a bit more conservative in solving constraints previously provided by superclasses (see #11762). For instance, consider this program,

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

class Super a
class (Super a) => Left a
class (Super a) => Right a
instance (Left a) => Right a    -- this is now an error

GHC now rejects the Right a instance, claiming it cannot deduce the Super a superclass constraint of the Right typeclass. This stands in contrast to previous releases, which would accept this declaration, using the Super a constraint implied by the Left a constraint. To fix this simply add the needed superclass constraint explicitly,

instance (Left a, Super a) => Right a


This flag has been removed and replaced by two flags -Wmissed-specialisations and -Wall-missed-specialisations.

Old GADT record syntax

The old syntax for record constructors for a GADT has been removed

-- Old Syntax
data G2 a :: * where
  G2A { g2a :: a, g2b :: Int } :: G2 a

-- New Syntax
data G2 a :: * where
  G2A :: { g2a :: a, g2b :: Int } -> G2 a

This flag was widely regarded as a misfeature, in prior versions it issued a deprecation warning, it is now not supported at all.

Old QuasiQuote syntax

The old syntax which allowed quotes to be prefixed by $ has been removed.

-- Old Syntax
foo = [$x| ... ] 

-- New Syntax
foo = [x| ... ]

Kind-level definitions shuffled around

If you're using various bits of magic from within GHC and importing from GHC.Prim (for example, for Constraint), you'll find that some definitions have moved around. There is a simple fix: import from GHC.Exts instead. That module re-exports all of GHC.Prim and a few other internal modules. This change is also backward-compatible.

Pattern Synonym Signatures

  1. The ordering of the constraints has been changed so that required constraints appear before provided constraints.
  1. A single set of constraints corresponds to a set of required rather than provided constraints.

For example:


pattern P1 :: prov => req => ty

pattern P2 :: prov => ty

pattern P3 :: ()  => req => ty

pattern P4 :: ty

-- after 

pattern P1 :: req => prov => ty

pattern P2 :: ()  => prov => ty

pattern P3 :: req => ty

pattern P4 :: ty

Library changes


Recommendations for forward-compatibility

TLDR: The gist of the following paragraphs is to add some variation of the following snippet to your .cabal file, and address the warnings emitted by GHC when compiling your package:

  if impl(ghc >= 8.0)
    ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
    -- provide/emulate `Control.Monad.Fail` and `Data.Semigroups` API for pre-GHC8
    build-depends: fail == 4.9.*, semigroups == 0.18.*

The following suggestions are not mandatory but recommended for those who wish to make their code-bases compatible and/or make use of newly added features starting with GHC 8.0 thereby increasing the chance of extending the compatibility window of their code-base early on.

Normalise Applicative/Monad instance definitions

base- continues to generalise functions from Monad to Applicative. However, in order to avoid performance regressions due to sub-optimally defined Applicative/Monad instances, it's highly advised to follow the AMP+MRP refactoring guidelines that were already provided in the GHC 7.10.x Migration Guide.

A new warning that needs to be enabled via -Wnoncanonical-monad-instances (not implied by -Wcompat) is available to help detect code which may be at risk.

Provide Semigroup/Monoid instances definitions

Starting with base-, Data.Semigroup has moved into base, kicking off the prime:Libraries/Proposals/SemigroupMonoid roadmap which will eventually lead to have Semigroup become a proper superclass of Monoid.

In order to smooth the transition, it's important to have Semigroup instances in place as soon as possible, especially in library packages. In order to aid detecting missing instances two warnings have been implemented in GHC 8.0 (both implied by -Wcompat): -Wnoncanonical-monoid-instances and -Wsemigroup. Those warnings also help defining the instances in compliance with the envisioned transition scheme.

The hackage:semigroups package can be used to avoid -XCPP usage by providing the same Data.Semigroup module for older GHCs.

Provide MonadFail instances

See prime:Libraries/Proposals/MonadFail for more details.

Again, in order to extend the compatibility window of your code it's recommended to provide instances early on. To this end, two warnings have been implemented to help with detecting code needing attention: -Wmissing-monadfail-instances (implied by -Wcompat) and -Wnoncanonical-monadfail-instances (not implied by -Wcompat).

The hackage:fail package helps avoiding -XCPP usage and emulates the new Control.Monad.Fail module.

Reworked HasCallStack API

GHC's callstack interface (formerly known as "implicit call stacks") is been reworked, hiding the implicit parameter behind a constraint synonym,

type HasCallStack = (?callStack :: CallStack) :: Constraint

Existing users of this functionality taking callStack arguments should be refactored to use this synonym if possible. This has the happy consequence that modules using this mechanism needn't enable ImplicitParams.

For instance,

{-# LANGUAGE ImplicitParams #-}
module AssertOdd where
import GHC.Stack (CallStack)
assertOdd :: (?callStack :: CallStack) => Int -> a -> a
assertOdd n
  | odd n     = id
  | otherwise = error "That number isn't odd!"

turns in to,

module AssertOdd where
import GHC.Stack (HasCallStack)
assertOdd :: HasCallStack => Int -> a -> a
assertOdd n
  | odd n     = id
  | otherwise = error "That number isn't odd!"

New Generic metadata representation

GHC 8.0 changes the way GHC generics encodes metadata. Previously, an empty data type would be generated for every datatype, constructor, and record selector associated with a Generic instance. For example:

data Example a = Example a deriving Generic

would have generated the following code prior to GHC 8.0:

instance Generic (Example a) where
  type Rep (Example a) =
    D1 D1Example
      (C1 C1_0Example
        (S1 NoSelector (Rec0 a)))

data D1Example
data C1_0Example

instance Datatype D1Example where ...
instance Constructor C1_0Example where ...

GHC 8.0, on the other hand, does not generate empty data types. The M1 data type in GHC.Generics has been modified so that it is parameterized by a new Meta type:

data Meta = MetaData Symbol Symbol Symbol Bool
          | MetaCons Symbol FixityI Bool
          | MetaSel  (Maybe Symbol) SourceUnpackedness SourceStrictness DecidedStrictness

newtype M1 (i :: *) (c :: Meta) (f :: * -> *) (p :: *) = M1 { unM1 :: f p }
type D1 = M1 D
type C1 = M1 C
type S1 = M1 S

There is now only one instance for Datatype, Constructor, and Selector. (For more information on how this works, see this.)

instance Datatype ('MetaData n m p nt) where ...
instance Constructor ('MetaCons n f r) where ...
instance Selector ('MetaSel mn su ss ds) where ...

One major consequence of the additions to MetaSel is that the NoSelector datatype is insufficient to express all of the strictness properties of a record selector, so NoSelector was removed. If your generics-related code only mentions the Datatype, Constructor, and Selector typeclasses, it will not need to change. If your code does something more ambitious like checking for the presence of NoSelector, it will need to be updated to use MetaSel instead. For example, the above Example would have the following code generated:

instance Generic (Example a) where
  type Rep (Example a) =
    D1 ('MetaData "Example" "Module" "package" 'False)
      (C1 ('MetaCons "Example" 'PrefixI 'False)
        (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)
          (Rec0 a)))

Notice that since Example has no record selector, it generated ('MetaSel 'Nothing ...) instead of ('MetaSel ('Just "recordName") ...).


  • Three Info constructors (ClassOpI, DataConI, and VarI) no longer have a Fixity field. Instead, all Fixity information for a given Name is now determined through the reifyFixity function, which returns Just the fixity if there is an explicit fixity declaration for that Name, and Nothing otherwise.
  • the DataD, NewtypeD, DataInstD, and NewtypeInstD constructors have a new field Maybe Kind (#10828), and take a CxtQ instead of a [Name] for the derived classes (#10819). If you don't know what to do, use Nothing for the kind signature. The field that used to be of type [Name] can be converted to a CxtQ using mapM conT.
        - dataD :: CxtQ -> Name -> [TyVarBndr]               -> [ConQ] -> [Name] -> DecQ
        + dataD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> [ConQ] -> CxtQ   -> DecQ
        - newtypeD :: CxtQ -> Name -> [TyVarBndr]               -> ConQ -> [Name] -> DecQ
        + newtypeD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> ConQ -> CxtQ   -> DecQ
        - dataInstD :: CxtQ -> Name -> [TypeQ]               -> [ConQ] -> [Name] -> DecQ
        + dataInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> [ConQ] -> CxtQ   -> DecQ
        - newtypeInstD :: CxtQ -> Name -> [TypeQ]               -> ConQ -> [Name] -> DecQ
        + newtypeInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> ConQ -> CxtQ   -> DecQ
  • The Strict datatype has been overhauled. The functional equivalent of Strict in template-haskell- is Bang:
    data Bang = Bang SourceUnpackedness SourceStrictness
    data SourceUnpackedness
      = NoSourceUnpackedness -- ^ @C                  a@
      | SourceNoUnpack       -- ^ @C {-# NOUNPACK #-} a@
      | SourceUnpack         -- ^ @C {-# UNPACK #-}   a@
    data SourceStrictness = NoSourceStrictness    -- ^ @C  a@
                          | SourceLazy            -- ^ @C ~a@
                          | SourceStrict          -- ^ @C !a@
    type BangType    = (Bang, Type)
    type VarBangType = (Name, Bang, Type)
    Note that the notions of unpackedness and strictness, which were previously combined in Strict, have now been decoupled. Also note the emphasis on source, as Bang represents what the user writes in source code. A field's source strictness may be quite different from what GHC actually decides to use as a field's strictness.

For example, if -XStrict is enabled, GHC will decided that any field not marked with a laziness annotation (~) will become strict. So if you compile the following datatype with -XStrict enabled:

data Example a = Example a

GHC will decide that Example's field is strict. However, if you reify Example, its Bang value will be Bang NoSourceUnpackedness NoSourceStrictness because the user did not put an explicit strictness annotation (!) in the source code. To figure out what GHC decided, use the reifyConStrictness function:

reifyConStrictness :: Name -> Q [DecidedStrictness]

data DecidedStrictness = DecidedLazy
                       | DecidedStrict
                       | DecidedUnpack
  • The InstanceD constructor

    This was a late change introduced in GHC 8.0 RC4, see discussion for more details.

    of type Dec has an additional field of type Maybe Overlap. It is used to specify the overlapping behavior for the instances, as with the {-# OVERLAP/S/PED/PING #-} pragmas:
    data Dec = ... | InstanceD (Maybe Overlap) Cxt Type [Dec] | ...
    data Overlap = Overlappable | Overlapping | Overlaps | Incoherent
    Note that to reduce code breakage, and to support the common case, the corresponding instanceD function was not changed---it will produce instances where the "overlap" field is set to Nothing. To generate instances with a specific overlapping behavior, please use instanceWithOverlapD.

Tool changes

hsc2hs defines an #alignment macro

Starting with version 0.68 hackage:hsc2hs now supports the #alignment macro, which can be used to calculate the alignment of a struct in bytes. It is common for .hsc files to implement #alignment manually via a #let directive:

#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)

This command was incorporated into hsc2hs with the release of GHC 8.0. As a result, if you have the above directive in your code, it will now emit a warning when compiled with GHC 8.0:

Module.hsc:24:0: warning: "hsc_alignment" redefined [enabled by default]
In file included from dist/build/Module_hsc_make.c:1:0:
/path/to/ghc/lib/template-hsc.h:88:0: note: this is the location of the previous definition
 #define hsc_alignment(t...) \

To make your code free of warnings on GHC 8.0 and earlier versions, surround the directive with a pragma checking for the right GHC version:

#if __GLASGOW_HASKELL__ < 800
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)

GHC API changes

Not all changes, just potential gotchas.

con_names is no longer total for ConDecl

ConDecl now has two constructors, ConDeclGADT and ConDeclH98. The con_names field still exists for ConDeclGADT, but has become con_name for ConDeclH98.

So existing code will compile but break at runtime when processing a ConDeclH98.

The utility function getConNames should be used instead, which behaves like the old con_names.

Last modified 3 years ago Last modified on Jun 10, 2016 9:47:58 AM