|
|
[[_TOC_]]
|
|
|
|
|
|
# GHC 8.4.x Migration Guide
|
|
|
|
|
|
|
... | ... | @@ -12,8 +14,9 @@ This guide summarises the changes you may need to make to your code to migrate f |
|
|
|
|
|
The order in which type variables are quantified in GADT constructor type signatures has changed. Before, if you had `MkT` as below:
|
|
|
|
|
|
```
|
|
|
dataT a whereMkT:: forall b a. b ->T a
|
|
|
```hs
|
|
|
data T a where
|
|
|
MkT :: forall b a. b -> T a
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -24,9 +27,9 @@ Then the type of `MkT` would (counterintuitively) be `forall a b. b -> T a`! Now |
|
|
|
|
|
Some code which previously typechecked in earlier versions of GHC without the use of the `TypeInType` extension will now require it in 8.4. For example:
|
|
|
|
|
|
```
|
|
|
myError:: forall (r ::RuntimeRep). forall (a ::TYPE r).String-> a
|
|
|
myError=error
|
|
|
```hs
|
|
|
myError :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . String -> a
|
|
|
myError = error
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -35,8 +38,9 @@ In spirit, this function has always required the `TypeInType` extension, since t |
|
|
|
|
|
In addition, prior GHCs would permit this sort of GADT, where the GADT return type constrains a *kind* parameter, without the use of `TypeInType`:
|
|
|
|
|
|
```
|
|
|
dataG(a :: k)whereGInt::GInt
|
|
|
```hs
|
|
|
data G (a :: k) where
|
|
|
GInt :: G Int
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -47,7 +51,7 @@ Similarly, this now requires `TypeInType` in GHC 8.4. |
|
|
|
|
|
Before GHC 8.4, whether or not Template Haskell would reify a data type as a `GadtC` (or `RecGadtC`) was somewhat unpredictable, as it used heuristics to determine whether a data type was declared using GADT syntax or not. While this worked for most use cases, there were nevertheless some corner cases where a GADT would not be reified as a `GadtC`, and conversely, a non-GADT would be reified as a `GadtC`. For example:
|
|
|
|
|
|
```wiki
|
|
|
```
|
|
|
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
|
|
|
λ> :set -XTemplateHaskell -XExistentialQuantification -XGADTs
|
|
|
λ> import Language.Haskell.TH
|
... | ... | @@ -65,8 +69,9 @@ Note that `Foo`, a GADT, is *not* reified as a `GadtC`, whereas `Bar`, which is |
|
|
|
|
|
In accordance with the changes to GADT constructor type variable order (mentioned [above](https://gitlab.haskell.org/trac/ghc/wiki/Migration/8.4#TypevariableorderinGADTconstructors)), reified GADT constructors also now track the order in which users wrote type variables. Continuing the earlier example:
|
|
|
|
|
|
```
|
|
|
dataT a whereMkT:: forall b a. b ->T a
|
|
|
```hs
|
|
|
data T a where
|
|
|
MkT :: forall b a. b -> T a
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -84,93 +89,117 @@ As part of [this proposal](https://github.com/ghc-proposals/ghc-proposals/pull/6 |
|
|
- Derived `Eq` and `Ord` instances would previously emit code that used
|
|
|
`error`:
|
|
|
|
|
|
```
|
|
|
instanceEq(Empty a)where(==)=error"Void =="instanceOrd(Empty a)where
|
|
|
compare =error"Void compare"
|
|
|
```
|
|
|
```hs
|
|
|
instance Eq (Empty a) where
|
|
|
(==) = error "Void =="
|
|
|
|
|
|
instance Ord (Empty a) where
|
|
|
compare = error "Void compare"
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> Now, they emit code that uses maximally defined, lazier semantics:
|
|
|
Now, they emit code that uses maximally defined, lazier semantics:
|
|
|
|
|
|
```
|
|
|
instanceEq(Empty a)where_==_=TrueinstanceOrd(Empty a)where
|
|
|
compare __=EQ
|
|
|
```
|
|
|
```hs
|
|
|
instance Eq (Empty a) where
|
|
|
_ == _ = True
|
|
|
|
|
|
instance Ord (Empty a) where
|
|
|
compare _ _ = EQ
|
|
|
```
|
|
|
|
|
|
- Derived `Read` instances would previous emit code that used
|
|
|
`parens`:
|
|
|
|
|
|
```
|
|
|
instanceRead(Empty a)where
|
|
|
readPrec = parens pfail
|
|
|
```
|
|
|
```hs
|
|
|
instance Read (Empty a) where
|
|
|
readPrec = parens pfail
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> But `parens` forces parts of the parsed string that it doesn't need to.
|
|
|
> Now, the derived instance will not use `parens` (that it, parsing
|
|
|
> `Empty` will always fail, without reading \*any\* input):
|
|
|
But `parens` forces parts of the parsed string that it doesn't need to.
|
|
|
Now, the derived instance will not use `parens` (that it, parsing
|
|
|
`Empty` will always fail, without reading \*any\* input):
|
|
|
|
|
|
```
|
|
|
instanceRead(Empty a)where
|
|
|
readPrec = pfail
|
|
|
```
|
|
|
```hs
|
|
|
instance Read (Empty a) where
|
|
|
readPrec = pfail
|
|
|
```
|
|
|
|
|
|
- Derived `Show` instances would previously emit code that used
|
|
|
`error`:
|
|
|
|
|
|
```
|
|
|
instanceShow(Empty a)where
|
|
|
showsPrec ="Void showsPrec"
|
|
|
```
|
|
|
```hs
|
|
|
instance Show (Empty a) where
|
|
|
showsPrec = "Void showsPrec"
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> Now, they emit code that inspects the argument. That is, if the argument
|
|
|
> diverges, then showing it will also diverge:
|
|
|
Now, they emit code that inspects the argument. That is, if the argument
|
|
|
diverges, then showing it will also diverge:
|
|
|
|
|
|
```
|
|
|
instanceShow(Empty a)where
|
|
|
showsPrec _ x =case x of{}
|
|
|
```
|
|
|
```hs
|
|
|
instance Show (Empty a) where
|
|
|
showsPrec _ x = case x of {}
|
|
|
```
|
|
|
|
|
|
- Derived `Functor`, `Foldable`, `Traversable`, `Generic`,
|
|
|
`Generic1`, `Lift`, and `Data` instances previously emitted code that
|
|
|
used `error`:
|
|
|
|
|
|
```
|
|
|
instanceFunctorEmptywhere
|
|
|
fmap =error"Void fmap"instanceFoldableEmptywhere
|
|
|
foldMap =error"Void foldMap"instanceTraversableEmptywhere
|
|
|
traverse =error"Void traverse"instanceGeneric(Empty a)where
|
|
|
from =M1(error"No generic representation for empty datatype Empty")
|
|
|
to (M1_)=error"No values for empty datatype Empty"-- Similarly for Generic1instanceLift(Empty a)where
|
|
|
lift _=error"Can't lift value of empty datatype Empty"instanceData a =>Data(Empty a)where
|
|
|
gfoldl ___=error"Void gfoldl"
|
|
|
toConstr _=error"Void toConstr"...
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> Now, derived `Functor`, `Traversable, `Generic`, `Generic1\`,
|
|
|
> `Lift`, and `Data` instances emit code which inspects their
|
|
|
> arguments:
|
|
|
|
|
|
```
|
|
|
instanceFunctorEmptywhere
|
|
|
fmap _ x =case x of{}instanceTraversableEmptywhere
|
|
|
traverse _ x = pure (case x of{})instanceGeneric(Empty a)where
|
|
|
from x =M1(case x of{})
|
|
|
to (M1 x)=case x of{}-- Similarly for Generic1instanceLift(Empty a)where
|
|
|
lift x = pure (case x of{})instanceData a =>Data(Empty a)where
|
|
|
gfoldl _ x =case x of{}
|
|
|
toConstr x =case x of{}...
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> Derived `Foldable` instances now are maximally lazy:
|
|
|
|
|
|
```
|
|
|
instanceFoldableEmptywhere
|
|
|
foldMap __= mempty
|
|
|
```
|
|
|
```hs
|
|
|
instance Functor Empty where
|
|
|
fmap = error "Void fmap"
|
|
|
|
|
|
instance Foldable Empty where
|
|
|
foldMap = error "Void foldMap"
|
|
|
|
|
|
instance Traversable Empty where
|
|
|
traverse = error "Void traverse"
|
|
|
|
|
|
instance Generic (Empty a) where
|
|
|
from = M1 (error "No generic representation for empty datatype Empty")
|
|
|
to (M1 _) = error "No values for empty datatype Empty"
|
|
|
-- Similarly for Generic1
|
|
|
|
|
|
instance Lift (Empty a) where
|
|
|
lift _ = error "Can't lift value of empty datatype Empty"
|
|
|
|
|
|
instance Data a => Data (Empty a) where
|
|
|
gfoldl _ _ _ = error "Void gfoldl"
|
|
|
toConstr _ = error "Void toConstr"
|
|
|
...
|
|
|
```
|
|
|
|
|
|
Now, derived `Functor`, `Traversable, `Generic`, `Generic1\`,
|
|
|
`Lift`, and `Data` instances emit code which inspects their
|
|
|
arguments:
|
|
|
|
|
|
```hs
|
|
|
instance Functor Empty where
|
|
|
fmap _ x = case x of {}
|
|
|
|
|
|
instance Traversable Empty where
|
|
|
traverse _ x = pure (case x of {})
|
|
|
|
|
|
instance Generic (Empty a) where
|
|
|
from x = M1 (case x of {})
|
|
|
to (M1 x) = case x of {}
|
|
|
|
|
|
-- Similarly for Generic1
|
|
|
|
|
|
instance Lift (Empty a) where
|
|
|
lift x = pure (case x of {})
|
|
|
|
|
|
instance Data a => Data (Empty a) where
|
|
|
gfoldl _ x = case x of {}
|
|
|
toConstr x = case x of {}
|
|
|
...
|
|
|
```
|
|
|
|
|
|
Derived `Foldable` instances now are maximally lazy:
|
|
|
|
|
|
```hs
|
|
|
instance Foldable Empty where
|
|
|
foldMap _ _ = mempty
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
... | ... | @@ -183,7 +212,7 @@ instanceFoldableEmptywhere |
|
|
|
|
|
In order to future-proof your packages for upcoming changes, add the following snippet to your `.cabal` file, and address the warnings emitted by GHC when compiling your package:
|
|
|
|
|
|
```wiki
|
|
|
```
|
|
|
if impl(ghc >= 8.0)
|
|
|
ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
|
|
|
else
|
... | ... | @@ -221,42 +250,59 @@ As part of [ImplementingTreesThatGrow](implementing-trees-that-grow) the index t |
|
|
|
|
|
We now have
|
|
|
|
|
|
```
|
|
|
dataGhcPass(c ::Pass)dataPass=Parsed|Renamed|Typecheckedderiving(Data)
|
|
|
```hs
|
|
|
data GhcPass (c :: Pass)
|
|
|
|
|
|
data Pass = Parsed | Renamed | Typechecked
|
|
|
deriving (Data)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
and synonyms
|
|
|
|
|
|
```
|
|
|
typeGhcPs=GhcPass'Parsed-- Old 'RdrName' type paramtypeGhcRn=GhcPass'Renamed-- Old 'Name' type paramtypeGhcTc=GhcPass'Typechecked-- Old 'Id' type para,typeGhcTcId=GhcTc-- Old 'TcId' type param
|
|
|
```hs
|
|
|
type GhcPs = GhcPass 'Parsed -- Old 'RdrName' type param
|
|
|
type GhcRn = GhcPass 'Renamed -- Old 'Name' type param
|
|
|
type GhcTc = GhcPass 'Typechecked -- Old 'Id' type para,
|
|
|
type GhcTcId = GhcTc -- Old 'TcId' type param
|
|
|
```
|
|
|
|
|
|
|
|
|
So in practical terms, code will have to change as
|
|
|
|
|
|
```
|
|
|
fooParsed::HsDeclRdrNamefooRenamed::HsDeclNamefooTypechecked::HsDeclId
|
|
|
```hs
|
|
|
fooParsed :: HsDecl RdrName
|
|
|
fooRenamed :: HsDecl Name
|
|
|
fooTypechecked :: HsDecl Id
|
|
|
```
|
|
|
|
|
|
|
|
|
becomes
|
|
|
|
|
|
```
|
|
|
fooParsed::HsDeclGhcPsfooRenamed::HsDeclGhcRnfooTypechecked::HsDeclGhcTc
|
|
|
```hs
|
|
|
fooParsed :: HsDecl GhcPs
|
|
|
fooRenamed :: HsDecl GhcRn
|
|
|
fooTypechecked :: HsDecl GhcTc
|
|
|
```
|
|
|
|
|
|
|
|
|
The following code provides backward-compatible versions of the new synonyms
|
|
|
|
|
|
```
|
|
|
#if __GLASGOW_HASKELL__ <=802typeGhcPs=RdrNametypeGhcRn=NametypeGhcTc=Id#endif
|
|
|
```hs
|
|
|
#if __GLASGOW_HASKELL__ <= 802
|
|
|
type GhcPs = RdrName
|
|
|
type GhcRn = Name
|
|
|
type GhcTc = Id
|
|
|
#endif
|
|
|
```
|
|
|
|
|
|
|
|
|
There is also a type family to define the underlying identifier type for a given index.
|
|
|
|
|
|
```
|
|
|
typefamilyIdP p
|
|
|
typeinstanceIdPGhcPs=RdrNametypeinstanceIdPGhcRn=NametypeinstanceIdPGhcTc=Id
|
|
|
```hs
|
|
|
type family IdP p
|
|
|
type instance IdP GhcPs = RdrName
|
|
|
type instance IdP GhcRn = Name
|
|
|
type instance IdP GhcTc = Id
|
|
|
``` |
|
|
\ No newline at end of file |