Let's start by exploring several types:
coerce (+) :: (Num n, Coercible (n -> n -> n) b) => b myf :: F cd
The first problem is that the GHC has no hope of pinning n , so it can choose an implementation (+) .
Let's see what happens if we use region type variables for a simple solution:
myzip :: forall ab . Num b => F ab -> F ab myzip = coerce ((+) :: b -> b -> b) myf
This is not accepted. What for? Because myf type myf ambiguous! We can see this more clearly if we expand myzip into another argument:
myzip x = coerce ((+) :: b -> b -> b) myf x
From how Coercible works with type constructors ( -> , in this case), we can align everything and conclude that the type myf should be coercible with b , where x :: F ab . But the type myf in this context is ambiguous. Therefore, the GHC is not in a position to select the appropriate Coercible instance between b and the type for myf . Since coerce indeed an identification function under the hood, it does not matter which one is selected, but the GHC simply will not select an instance based on an ambiguous type variable. To make this work, you need something like
myzip :: forall ab . Num b => F ab -> F ab myzip = (coerce ((+) :: b -> b -> b)) (myf :: F ab)
Role type
Type roles cannot (at least for the time being) determine instance resolution. All they can do is determine which Coercible instances are created. Considering,
class c => X d
GHC concludes that X d entails c . But considering
instance c => X d
The GHC will not conclude that X d entails c . I am not sure of the details of why, but this has always been the case.
source share