... | @@ -45,4 +45,55 @@ NB: ‘F’ is a non-injective type family |
... | @@ -45,4 +45,55 @@ NB: ‘F’ is a non-injective type family |
|
The type variable ‘b0’ is ambiguous
|
|
The type variable ‘b0’ is ambiguous
|
|
```
|
|
```
|
|
|
|
|
|
To fix these issues, add a type signature to the expression that the record update is applied to (`emptyT` in the example above), or add an injectivity annotation to the type family in the case that the type family is in fact injective. |
|
To fix these issues, add a type signature to the expression that the record update is applied to (`emptyT` in the example above), or add an injectivity annotation to the type family in the case that the type family is in fact injective.
|
|
\ No newline at end of file |
|
|
|
|
|
### Superclass expansion is more conservative
|
|
|
|
|
|
|
|
GHC 9.6 is more careful about expanding superclasses involving type families so as to avoid potentially infinite loops during typechecking. Here is an example (minimized from the `futhark` library):
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
data Aliases (rep :: Type)
|
|
|
|
|
|
|
|
class Show (Op l) => RepTypes (l :: Type) where
|
|
|
|
type Op l :: Type
|
|
|
|
|
|
|
|
class Show (OpWithAliases op) => CanBeAliased op where
|
|
|
|
type OpWithAliases op :: Type
|
|
|
|
|
|
|
|
instance CanBeAliased (Op rep) => RepTypes (Aliases rep) where
|
|
|
|
type Op (Aliases rep) = OpWithAliases (Op rep)
|
|
|
|
```
|
|
|
|
|
|
|
|
In order to typecheck the `RepTypes (Aliases rep)` instance, GHC must solve solve its `Show (Op (Aliases rep))` superclass. This is referred to as a *Wanted* constraint. After expanding `Op (Aliases rep)`, this Wanted constraint would become `Show (OpWithAliases (Op rep))`.
|
|
|
|
|
|
|
|
In order to solve this Wanted constraint, GHC must use the instance context `CanBeAliased (Op rep)`. This is referred to as a *Given* constraint. After expanding the superclass of `CanBeAliased`, this Given constraint would become `Show (OpWithAliases (Op rep))`.
|
|
|
|
|
|
|
|
Note that this Given is the same as the Wanted constraint we are trying to solve for! Previous versions of GHC would do this superclass expansion without any further scrutiny. GHC 9.6, however, will refuse this instance as written:
|
|
|
|
|
|
|
|
```
|
|
|
|
[1 of 1] Compiling Foo ( Foo.hs, Foo.o )
|
|
|
|
|
|
|
|
Foo.hs:15:10: error: [GHC-39999]
|
|
|
|
• Could not deduce ‘Show (OpWithAliases (Op rep))’
|
|
|
|
arising from the superclasses of an instance declaration
|
|
|
|
from the context: CanBeAliased (Op rep)
|
|
|
|
bound by the instance declaration at Foo.hs:15:10-56
|
|
|
|
Possible fix:
|
|
|
|
If the constraint looks soluble from a superclass of the instance context,
|
|
|
|
read 'Undecidable instances and loopy superclasses' in the user manual
|
|
|
|
• In the instance declaration for ‘RepTypes (Aliases rep)’
|
|
|
|
|
|
|
|
|
15 | instance CanBeAliased (Op rep) => RepTypes (Aliases rep) where
|
|
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
```
|
|
|
|
|
|
|
|
This is because when typechecking instances, GHC will only expand superclasses of Given constraints if it is *Patterson-smaller* than the instance head. In this example, the `CanBeAliased (Op rep)` Given constraint is not Patterson-smaller than the instance head `RepTypes (Aliases rep)`, so GHC will not expand the superclasses of the Given constraint. For more information on what "Patterson-smaller" means, refer to the [Undecidable instances and loopy superclasses](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/instances.html?highlight=overlapping%20instance#undecidable-instances-and-loopy-superclasses) section of the GHC User's Guide.
|
|
|
|
|
|
|
|
To repair the instance above, one can simply add `Show (OpWithAliases (Op rep))` to the instance context like so:
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
instance (CanBeAliased (Op rep), Show (OpWithAliases (Op rep))) => RepTypes (Aliases rep) where
|
|
|
|
-- ...
|
|
|
|
```
|
|
|
|
|
|
|
|
This fix is perhaps a bit surprising, as the `Show (OpWithAliases (Op rep))` constraint might seem redundant. But it is actually *not* redundant, precisely because GHC will not expand superclasses in the `CanBeAliased (Op rep)` constraint. |
|
|
|
\ No newline at end of file |