|
|
[[_TOC_]]
|
|
|
|
|
|
# GHC 8.2.x Migration Guide
|
|
|
|
|
|
|
... | ... | @@ -12,25 +14,25 @@ This guide summarises the changes you may need to make to your code to migrate f |
|
|
|
|
|
There a new validity check for default class method implementations using `-XDefaultSignatures`. In particular, if you have a class `Foo`:
|
|
|
|
|
|
```
|
|
|
classFoo a where
|
|
|
bar ::C=> a -> b -> b
|
|
|
```hs
|
|
|
class Foo a where
|
|
|
bar :: C => a -> b -> b
|
|
|
```
|
|
|
|
|
|
|
|
|
and you add a default type signature for `bar`, it *must* be of the form:
|
|
|
|
|
|
```
|
|
|
default bar ::C'=> a -> b -> b
|
|
|
```hs
|
|
|
default bar :: C' => a -> b -> b
|
|
|
```
|
|
|
|
|
|
|
|
|
That is, the right-hand sides of the type signatures must be the same, but the contexts `C` and `C'` are allowed to be different. That means that these default type signatures for `bar`:
|
|
|
|
|
|
```
|
|
|
default bar ::C'=> b -> a -> b
|
|
|
default bar ::C'=> b -> b -> a
|
|
|
default bar ::C'=> a -> b -> b -> b
|
|
|
```hs
|
|
|
default bar :: C' => b -> a -> b
|
|
|
default bar :: C' => b -> b -> a
|
|
|
default bar :: C' => a -> b -> b -> b
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -39,16 +41,17 @@ will all be rejected. |
|
|
|
|
|
These will also be rejected:
|
|
|
|
|
|
```
|
|
|
default bar ::C'=> a ->Int->Intdefault bar ::C'=> a ->TF b ->TF b
|
|
|
```hs
|
|
|
default bar :: C' => a -> Int -> Int
|
|
|
default bar :: C' => a -> TF b -> TF b
|
|
|
```
|
|
|
|
|
|
|
|
|
(where `TF` is a type family). But it's possible to rearrange these into equivalent forms that GHC accepts: just use type equalities!
|
|
|
|
|
|
```
|
|
|
default bar ::(C', b ~Int)=> a -> b -> b
|
|
|
default bar ::(C', b ~TF c)=> a -> b -> b
|
|
|
```hs
|
|
|
default bar :: (C', b ~ Int) => a -> b -> b
|
|
|
default bar :: (C', b ~ TF c) => a -> b -> b
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -59,38 +62,45 @@ As shown in the `TF` example, you might have to create new type variables (e.g., |
|
|
|
|
|
There is also a new validity check for associated type family instances. That is, if you have a class with an associated type family:
|
|
|
|
|
|
```
|
|
|
classC a b wheretypeT a x b
|
|
|
```hs
|
|
|
class C a b where
|
|
|
type T a x b
|
|
|
```
|
|
|
|
|
|
|
|
|
And you create and instance of `C`:
|
|
|
|
|
|
```
|
|
|
instanceC ty1 ty2 where...
|
|
|
```hs
|
|
|
instance C ty1 ty2 where ...
|
|
|
```
|
|
|
|
|
|
|
|
|
Then the associated `T` instance must look *exactly* like:
|
|
|
|
|
|
```
|
|
|
typeT ty1 v ty2 =...-- 'ty1' for 'a'-- 'ty2' for 'b', and-- some type `v` for 'x'
|
|
|
```hs
|
|
|
type T ty1 v ty2 = ...
|
|
|
-- 'ty1' for 'a'
|
|
|
-- 'ty2' for 'b', and
|
|
|
-- some type `v` for 'x'
|
|
|
```
|
|
|
|
|
|
|
|
|
As a concrete example, this code, which would have been allowed before GHC 8.2, is now disallowed:
|
|
|
|
|
|
```
|
|
|
classFoo a wheretypeBar a
|
|
|
```hs
|
|
|
class Foo a where
|
|
|
type Bar a
|
|
|
|
|
|
instanceFoo(Either a b)wheretypeBar(Either c d)= d -> c
|
|
|
instance Foo (Either a b) where
|
|
|
type Bar (Either c d) = d -> c
|
|
|
```
|
|
|
|
|
|
|
|
|
To fix this instance, simply use the same type variables in the `Bar` instance as in the instance head:
|
|
|
|
|
|
```
|
|
|
instanceFoo(Either a b)wheretypeBar(Either a b)= b -> a
|
|
|
```hs
|
|
|
instance Foo (Either a b) where
|
|
|
type Bar (Either a b) = b -> a
|
|
|
```
|
|
|
|
|
|
### Instances for class synonyms are now disallowed
|
... | ... | @@ -98,8 +108,12 @@ instanceFoo(Either a b)wheretypeBar(Either a b)= b -> a |
|
|
|
|
|
Previously, GHC silently accepted nonsense instance declarations like this:
|
|
|
|
|
|
```
|
|
|
typeReadShow a =(Read a,Show a)instanceReadFooinstanceShowFooinstanceReadShowFoo
|
|
|
```hs
|
|
|
type ReadShow a = (Read a, Show a)
|
|
|
|
|
|
instance Read Foo
|
|
|
instance Show Foo
|
|
|
instance ReadShow Foo
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -108,8 +122,9 @@ It's not even clear what this is supposed to mean, since `ReadShow` isn't a clas |
|
|
|
|
|
This check is a bit conservative, as it bars you from writing this as well:
|
|
|
|
|
|
```
|
|
|
typeMyShow=ShowinstanceMyShowFoo
|
|
|
```hs
|
|
|
type MyShow = Show
|
|
|
instance MyShow Foo
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -120,21 +135,27 @@ The workaround is to define the instance using `Show` instead of `MyShow`. |
|
|
|
|
|
The `MonoLocalBinds` extension, which places limitations on when the type of a term is generalized, also affects when the kind of a type signature of generalized. Prior to GHC 8.2, there were certain scenarios when kinds signatures were incorrectly generalized in the presence of `MonoLocalBinds`. This bug has now been fixed, but as a consequence, there are a handful of programs which will fail to typecheck without explicit kind signatures. Here is a known example:
|
|
|
|
|
|
```
|
|
|
{-# LANGUAGE InstanceSigs #-}{-# LANGUAGE MonoLocalBinds #-}{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE TypeInType #-}dataProxy a =ProxynewtypeTagged s b =Tagged b
|
|
|
```hs
|
|
|
{-# LANGUAGE InstanceSigs #-}
|
|
|
{-# LANGUAGE MonoLocalBinds #-}
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
{-# LANGUAGE TypeInType #-}
|
|
|
|
|
|
classC b where
|
|
|
c :: forall (s :: k).Tagged s b
|
|
|
data Proxy a = Proxy
|
|
|
newtype Tagged s b = Tagged b
|
|
|
|
|
|
instanceC(Proxy a)where
|
|
|
c :: forall s.Tagged s (Proxy a)
|
|
|
c =TaggedProxy
|
|
|
class C b where
|
|
|
c :: forall (s :: k). Tagged s b
|
|
|
|
|
|
instance C (Proxy a) where
|
|
|
c :: forall s. Tagged s (Proxy a)
|
|
|
c = Tagged Proxy
|
|
|
```
|
|
|
|
|
|
|
|
|
This compiles in GHC 8.0, but in GHC 8.2, it gives this error:
|
|
|
|
|
|
```wiki
|
|
|
```
|
|
|
• Couldn't match type ‘k0’ with ‘k1’
|
|
|
because type variable ‘k1’ would escape its scope
|
|
|
This (rigid, skolem) type variable is bound by
|
... | ... | @@ -156,10 +177,10 @@ The reason for this error is that the type signature for `c` captures `a`, an ou |
|
|
|
|
|
This can be worked around by specifying an explicit kind variable for `s`, e.g.,
|
|
|
|
|
|
```
|
|
|
instanceC(Proxy a)where
|
|
|
c :: forall (s :: k).Tagged s (Proxy a)
|
|
|
c =TaggedProxy
|
|
|
```hs
|
|
|
instance C (Proxy a) where
|
|
|
c :: forall (s :: k). Tagged s (Proxy a)
|
|
|
c = Tagged Proxy
|
|
|
```
|
|
|
|
|
|
---
|
... | ... | @@ -173,7 +194,7 @@ instanceC(Proxy a)where |
|
|
|
|
|
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
|
... | ... | @@ -197,15 +218,16 @@ See [wiki:Migration/8.0\#base-4.9.0.0](migration/8.0#) for more details |
|
|
|
|
|
The type signature of `fromLabel` has changed:
|
|
|
|
|
|
```
|
|
|
fromLabel::Proxy# x -> a -- old type signaturefromLabel:: a -- new type signature
|
|
|
```hs
|
|
|
fromLabel :: Proxy# x -> a -- old type signature
|
|
|
fromLabel :: a -- new type signature
|
|
|
```
|
|
|
|
|
|
>
|
|
|
> The new `fromLabel` can be accommodated using `TypeApplications`:
|
|
|
The new `fromLabel` can be accommodated using `TypeApplications`:
|
|
|
|
|
|
```
|
|
|
fromLabel(proxy#::Proxy#"foo"):: alpha -- old stylefromLabel@"foo":: alpha -- new style
|
|
|
```hs
|
|
|
fromLabel (proxy# :: Proxy# "foo") :: alpha -- old style
|
|
|
fromLabel @"foo" :: alpha -- new style
|
|
|
```
|
|
|
|
|
|
#### `GHC.Generics` is more polykinded
|
... | ... | @@ -213,51 +235,77 @@ fromLabel(proxy#::Proxy#"foo"):: alpha -- old stylefromLabel@"foo":: alpha -- ne |
|
|
|
|
|
The `Generic1` class, as well related classes and data types from `GHC.Generics`, are now poly-kinded. Here are the kind signatures of these types before `base-4.10.0.0`:
|
|
|
|
|
|
```
|
|
|
classGeneric1(f ::*->*)wheretypeRep1 f ::*->*
|
|
|
from1 :: f a ->Rep1 f a
|
|
|
to1 ::Rep1 f a -> f a
|
|
|
|
|
|
classDatatype(d :: k)where
|
|
|
datatypeName :: t d (f ::*->*)(a :: k1)->[Char]
|
|
|
moduleName :: t d (f ::*->*)(a :: k1)->[Char]
|
|
|
packageName :: t d (f ::*->*)(a :: k1)->[Char]
|
|
|
isNewtype :: t d (f ::*->*)(a :: k1)->BoolclassConstructor(c :: k)where
|
|
|
conName :: t c (f ::*->*)(a :: k1)->[Char]
|
|
|
conFixity :: t c (f ::*->*)(a :: k1)->Fixity
|
|
|
conIsRecord :: t c (f ::*->*)(a :: k1)->BoolclassSelector(s :: k)where
|
|
|
selName :: t s (f ::*->*)(a :: k1)->[Char]
|
|
|
selSourceUnpackedness :: t s (f ::*->*)(a :: k1)->SourceUnpackedness
|
|
|
selSourceStrictness :: t s (f ::*->*)(a :: k1)->SourceStrictness
|
|
|
selDecidedStrictness :: t s (f ::*->*)(a :: k1)->DecidedStrictnessdataV1(p ::*)dataU1(p ::*)=U1newtypePar1 p =Par1 p
|
|
|
newtypeRec1(f ::*->*)(p ::*)=Rec1(f p)newtypeK1 i c (p ::*)=K1 c
|
|
|
newtypeM1 i c (f ::*->*)(p ::*)=M1(f p)data(:+:)(f ::*->*)(g ::*->*)(p ::*)=L1(f p)|R1(g p)data(:*:)(f ::*->*)(g ::*->*)(p ::*)= f p :*: g p
|
|
|
newtype(:.:)(f ::*->*)(g ::*->*)(p ::*)=Comp1(f (g p))datafamilyURec a (p ::*)
|
|
|
```hs
|
|
|
class Generic1 (f :: * -> *) where
|
|
|
type Rep1 f :: * -> *
|
|
|
from1 :: f a -> Rep1 f a
|
|
|
to1 :: Rep1 f a -> f a
|
|
|
|
|
|
class Datatype (d :: k) where
|
|
|
datatypeName :: t d (f :: * -> *) (a :: k1) -> [Char]
|
|
|
moduleName :: t d (f :: * -> *) (a :: k1) -> [Char]
|
|
|
packageName :: t d (f :: * -> *) (a :: k1) -> [Char]
|
|
|
isNewtype :: t d (f :: * -> *) (a :: k1) -> Bool
|
|
|
|
|
|
class Constructor (c :: k) where
|
|
|
conName :: t c (f :: * -> *) (a :: k1) -> [Char]
|
|
|
conFixity :: t c (f :: * -> *) (a :: k1) -> Fixity
|
|
|
conIsRecord :: t c (f :: * -> *) (a :: k1) -> Bool
|
|
|
|
|
|
class Selector (s :: k) where
|
|
|
selName :: t s (f :: * -> *) (a :: k1) -> [Char]
|
|
|
selSourceUnpackedness :: t s (f :: * -> *) (a :: k1) -> SourceUnpackedness
|
|
|
selSourceStrictness :: t s (f :: * -> *) (a :: k1) -> SourceStrictness
|
|
|
selDecidedStrictness :: t s (f :: * -> *) (a :: k1) -> DecidedStrictness
|
|
|
|
|
|
data V1 (p :: *)
|
|
|
data U1 (p :: *) = U1
|
|
|
newtype Par1 p = Par1 p
|
|
|
newtype Rec1 (f :: * -> *) (p :: *) = Rec1 (f p)
|
|
|
newtype K1 i c (p :: *) = K1 c
|
|
|
newtype M1 i c (f :: * -> *) (p :: *) = M1 (f p)
|
|
|
data (:+:) (f :: * -> *) (g :: * -> *) (p :: *) = L1 (f p) | R1 (g p)
|
|
|
data (:*:) (f :: * -> *) (g :: * -> *) (p :: *) = f p :*: g p
|
|
|
newtype (:.:) (f :: * -> *) (g :: * -> *) (p :: *) = Comp1 (f (g p))
|
|
|
data family URec a (p :: *)
|
|
|
```
|
|
|
|
|
|
|
|
|
And here are their kind signatures now:
|
|
|
|
|
|
```
|
|
|
classGeneric1(f :: k ->*)wheretypeRep1 f :: k ->*
|
|
|
from1 :: f a ->Rep1 f a
|
|
|
to1 ::Rep1 f a -> f a
|
|
|
|
|
|
classDatatype(d :: k)where
|
|
|
datatypeName :: t d (f :: k1 ->*)(a :: k1)->[Char]
|
|
|
moduleName :: t d (f :: k1 ->*)(a :: k1)->[Char]
|
|
|
packageName :: t d (f :: k1 ->*)(a :: k1)->[Char]
|
|
|
isNewtype :: t d (f :: k1 ->*)(a :: k1)->BoolclassConstructor(c :: k)where
|
|
|
conName :: t c (f :: k1 ->*)(a :: k1)->[Char]
|
|
|
conFixity :: t c (f :: k1 ->*)(a :: k1)->Fixity
|
|
|
conIsRecord :: t c (f :: k1 ->*)(a :: k1)->BoolclassSelector(s :: k)where
|
|
|
selName :: t s (f :: k1 ->*)(a :: k1)->[Char]
|
|
|
selSourceUnpackedness :: t s (f :: k1 ->*)(a :: k1)->SourceUnpackedness
|
|
|
selSourceStrictness :: t s (f :: k1 ->*)(a :: k1)->SourceStrictness
|
|
|
selDecidedStrictness :: t s (f :: k1 ->*)(a :: k1)->DecidedStrictnessdataV1(p :: k)dataU1(p :: k)=U1newtypePar1 p =Par1 p
|
|
|
newtypeRec1(f :: k ->*)(p :: k)=Rec1(f p)newtypeK1 i c (p :: k)=K1 c
|
|
|
newtypeM1 i c (f :: k ->*)(p :: k)=M1(f p)data(:+:)(f :: k ->*)(g :: k ->*)(p :: k)=L1(f p)|R1(g p)data(:*:)(f :: k ->*)(g :: k ->*)(p :: k)= f p :*: g p
|
|
|
newtype(:.:)(f :: k2 ->*)(g :: k1 -> k2)(p :: k1)=Comp1(f (g p))datafamilyURec a (p :: k)
|
|
|
```hs
|
|
|
class Generic1 (f :: k -> *) where
|
|
|
type Rep1 f :: k -> *
|
|
|
from1 :: f a -> Rep1 f a
|
|
|
to1 :: Rep1 f a -> f a
|
|
|
|
|
|
class Datatype (d :: k) where
|
|
|
datatypeName :: t d (f :: k1 -> *) (a :: k1) -> [Char]
|
|
|
moduleName :: t d (f :: k1 -> *) (a :: k1) -> [Char]
|
|
|
packageName :: t d (f :: k1 -> *) (a :: k1) -> [Char]
|
|
|
isNewtype :: t d (f :: k1 -> *) (a :: k1) -> Bool
|
|
|
|
|
|
class Constructor (c :: k) where
|
|
|
conName :: t c (f :: k1 -> *) (a :: k1) -> [Char]
|
|
|
conFixity :: t c (f :: k1 -> *) (a :: k1) -> Fixity
|
|
|
conIsRecord :: t c (f :: k1 -> *) (a :: k1) -> Bool
|
|
|
|
|
|
class Selector (s :: k) where
|
|
|
selName :: t s (f :: k1 -> *) (a :: k1) -> [Char]
|
|
|
selSourceUnpackedness :: t s (f :: k1 -> *) (a :: k1) -> SourceUnpackedness
|
|
|
selSourceStrictness :: t s (f :: k1 -> *) (a :: k1) -> SourceStrictness
|
|
|
selDecidedStrictness :: t s (f :: k1 -> *) (a :: k1) -> DecidedStrictness
|
|
|
|
|
|
data V1 (p :: k)
|
|
|
data U1 (p :: k) = U1
|
|
|
newtype Par1 p = Par1 p
|
|
|
newtype Rec1 (f :: k -> *) (p :: k) = Rec1 (f p)
|
|
|
newtype K1 i c (p :: k) = K1 c
|
|
|
newtype M1 i c (f :: k -> *) (p :: k) = M1 (f p)
|
|
|
data (:+:) (f :: k -> *) (g :: k -> *) (p :: k) = L1 (f p) | R1 (g p)
|
|
|
data (:*:) (f :: k -> *) (g :: k -> *) (p :: k) = f p :*: g p
|
|
|
newtype (:.:) (f :: k2 -> *) (g :: k1 -> k2) (p :: k1) = Comp1 (f (g p))
|
|
|
data family URec a (p :: k)
|
|
|
```
|
|
|
|
|
|
|
... | ... | @@ -270,8 +318,7 @@ It's possible that you might experience some typechecker errors due to this chan |
|
|
- Due to the introduction of [deriving strategies](https://gitlab.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies), data types can now accept multiple deriving clauses (hence the need for `[DerivCxtQ]` instead of `DerivCxtQ`).
|
|
|
- Each deriving clause now allows an optional strategy keyword, so a new `DerivClause` data type was introduced that contains a `Maybe DerivStrategy` in addition to the usual `Cxt`.
|
|
|
|
|
|
>
|
|
|
> Similarly, the `StandaloneDerivD` constructor now also takes an additional `Maybe DerivStrategy` argument, since deriving strategy keywords can also be used with standalone `deriving` declarations. The `standaloneDerivD` function's type signature remains unchanged, as it will produce a standalone deriving declaration with no strategy keyword. If you want to use an explicit keyword, use `standaloneDerivWithStrategyD`.
|
|
|
Similarly, the `StandaloneDerivD` constructor now also takes an additional `Maybe DerivStrategy` argument, since deriving strategy keywords can also be used with standalone `deriving` declarations. The `standaloneDerivD` function's type signature remains unchanged, as it will produce a standalone deriving declaration with no strategy keyword. If you want to use an explicit keyword, use `standaloneDerivWithStrategyD`.
|
|
|
|
|
|
---
|
|
|
|
... | ... | |