... | ... | @@ -10,10 +10,13 @@ This guide summarises the changes you may need to make to your code to migrate f |
|
|
### Type variable order in GADT constructors
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
data T a where
|
|
|
MkT :: forall b a. b -> T a
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -22,21 +25,26 @@ Then the type of `MkT` would (counterintuitively) be `forall a b. b -> T a`! Now |
|
|
### `TypeInType` is pickier
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
myError :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . String -> a
|
|
|
myError = error
|
|
|
```
|
|
|
|
|
|
|
|
|
In spirit, this function has always required the `TypeInType` extension, since the type variable `r` is also used as a kind variable in `forall (a :: TYPE r)`. However, GHC mistakenly didn't require the explicit use of `TypeInType` here in earlier versions. This has been rectified in 8.4, so now `myError` will not typecheck without `TypeInType` being explicitly enabled.
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
data G (a :: k) where
|
|
|
GInt :: G Int
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -63,10 +71,13 @@ GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help |
|
|
Note that `Foo`, a GADT, is *not* reified as a `GadtC`, whereas `Bar`, which is not a GADT, *is* reified as a `GadtC`. In GHC 8.4, this bug has been fixed, so as a result, `Foo` will be reified as a `GadtC`, but `Bar` will not be, as one would expect.
|
|
|
|
|
|
|
|
|
|
|
|
In accordance with the changes to GADT constructor type variable order (mentioned [ above](https://ghc.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
|
|
|
data T a where
|
|
|
MkT :: forall b a. b -> T a
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -85,33 +96,45 @@ As part of [ this proposal](https://github.com/ghc-proposals/ghc-proposals/pull/ |
|
|
`error`:
|
|
|
|
|
|
```
|
|
|
instanceEq(Empty a)where(==)=error"Void =="instanceOrd(Empty a)where
|
|
|
compare =error"Void compare"
|
|
|
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:
|
|
|
>
|
|
|
>
|
|
|
|
|
|
```
|
|
|
instanceEq(Empty a)where_==_=TrueinstanceOrd(Empty a)where
|
|
|
compare __=EQ
|
|
|
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
|
|
|
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):
|
|
|
>
|
|
|
>
|
|
|
|
|
|
```
|
|
|
instanceRead(Empty a)where
|
|
|
instance Read (Empty a) where
|
|
|
readPrec = pfail
|
|
|
```
|
|
|
|
... | ... | @@ -119,17 +142,20 @@ instanceRead(Empty a)where |
|
|
`error`:
|
|
|
|
|
|
```
|
|
|
instanceShow(Empty a)where
|
|
|
showsPrec ="Void showsPrec"
|
|
|
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:
|
|
|
>
|
|
|
>
|
|
|
|
|
|
```
|
|
|
instanceShow(Empty a)where
|
|
|
showsPrec _ x =case x of{}
|
|
|
instance Show (Empty a) where
|
|
|
showsPrec _ x = case x of {}
|
|
|
```
|
|
|
|
|
|
- Derived `Functor`, `Foldable`, `Traversable`, `Generic`,
|
... | ... | @@ -137,39 +163,68 @@ instanceShow(Empty a)where |
|
|
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"...
|
|
|
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:
|
|
|
>
|
|
|
>
|
|
|
|
|
|
```
|
|
|
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{}...
|
|
|
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:
|
|
|
>
|
|
|
>
|
|
|
|
|
|
```
|
|
|
instanceFoldableEmptywhere
|
|
|
foldMap __= mempty
|
|
|
instance Foldable Empty where
|
|
|
foldMap _ _ = mempty
|
|
|
```
|
|
|
|
|
|
---
|
... | ... | @@ -219,44 +274,68 @@ The kind-monomorphic `Typeable[1-7]` classes, which were deprecated in GHC 7.8, |
|
|
As part of [ImplementingTreesThatGrow](implementing-trees-that-grow) the index type for the hsSyn AST has been changed.
|
|
|
|
|
|
|
|
|
|
|
|
We now have
|
|
|
|
|
|
|
|
|
```
|
|
|
dataGhcPass(c ::Pass)dataPass=Parsed|Renamed|Typecheckedderiving(Data)
|
|
|
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
|
|
|
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
|
|
|
fooParsed :: HsDecl RdrName
|
|
|
fooRenamed :: HsDecl Name
|
|
|
fooTypechecked :: HsDecl Id
|
|
|
```
|
|
|
|
|
|
|
|
|
becomes
|
|
|
|
|
|
|
|
|
```
|
|
|
fooParsed::HsDeclGhcPsfooRenamed::HsDeclGhcRnfooTypechecked::HsDeclGhcTc
|
|
|
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
|
|
|
#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
|
|
|
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 |