Using nominal roles for type inference

I have a newtype with type phantom, but I have problems using it.

Consider the following example:

 import Data.Coerce newtype F ab = F b myzip :: (Num b) => F ab -> F ab myzip = (coerce (+)) myf myf :: F ab myf = undefined 

The GHC complains that it Couldn't match representation of type 'a0' with that of 'Int' . Basically, the type is coerce (+) F a0 -> F a -> F a and not the type I want, F a -> F a -> F a .

Given the current role of a phantom , this is reasonable. I am wondering if there is an easy way to get type inference (I don't want to write signatures, so I use coerce in the first place!) In some other way. In particular, I expected that if I limited the role of parameter a nominal, then the GHC could say that the only possible choice for signature was the one I wanted. There is no such luck: GHC gives the same error.

In case that matters, in my real code the role of a should be at least representative, and b should be nominal.

+5
source share
1 answer

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.

+6
source

All Articles