使用名义角色进行类型推断

时间:2015-09-15 21:39:52

标签: haskell ghc

我有一个幻影类型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必须是名义上的。

1 个答案:

答案 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无法在myfCoercible的类型之间选择适当的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。我不确定原因的细节,但情况一直如此。