我有一个幻影类型newtype
,但我很难轻易使用它。
考虑以下示例:
import Data.Coerce
newtype F a b = F b
myzip :: (Num b) => F a b -> F a b
myzip = (coerce (+)) myf
myf :: F a b
myf = undefined
GHC抱怨它Couldn't match representation of type ‘a0’ with that of ‘Int’
。基本上,coerce (+)
的类型是F a0 -> F a -> F a
,而不是我想要的类型F a -> F a -> F a
。
鉴于a
phantom
的当前角色,这是合理的。我想知道是否有一种简单的方式来进行类型推断(我不想写出签名,这就是我使用coerce
的原因首先!)通过其他方法。
特别是,我预计如果我将参数a
的作用限制在名义上,那么GHC就能够告诉签名唯一可能的选择是我想要的。没有这样的运气:GHC给出了同样的错误。
如果重要的是,在我的真实代码中,a
的角色必须至少具有代表性,b
必须是名义上的。
答案 0 :(得分:6)
让我们先来看看几种类型:
coerce (+) :: (Num n, Coercible (n -> n -> n) b) => b
myf :: F c d
第一个问题是GHC无法确定n
,因此可以选择(+)
的实施。
让我们看看如果我们使用范围类型变量来尝试一个简单的解决方案会发生什么:
myzip :: forall a b . Num b => F a b -> F a b
myzip = coerce ((+) :: b -> b -> b) myf
这是不被接受的。为什么?因为myf
的类型不明确!如果我们用另一个参数扩展myzip
,我们可以更清楚地看到这一点:
myzip x = coerce ((+) :: b -> b -> b) myf x
从Coercible
使用类型构造函数(在这种情况下为->
)开始,我们可以排列所有内容并得出结论myf
的类型必须与{{1}一致其中b
。但是在这种情况下x :: F a b
的类型是模棱两可的。因此,GHC无法在myf
和Coercible
的类型之间选择适当的b
实例。因为myf
实际上是身份识别功能,所以选择哪一个重要,但GHC根本不会选择基于模糊类型变量的实例。要使这项工作,你需要像
coerce
类型角色不能(至少目前)以任何方式指导实例解析。他们所能做的只是确定生成的myzip :: forall a b . Num b => F a b -> F a b
myzip = (coerce ((+) :: b -> b -> b)) (myf :: F a b)
个实例。给定
Coercible
GHC将得出结论:class c => X d
需要X d
。但是给出了
c
GHC将不得出结论instance c => X d
需要X d
。我不确定原因的细节,但情况一直如此。