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

cro*_*eea 5 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
Run Code Online (Sandbox Code Playgroud)

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必须是名义上的.

dfe*_*uer 6

让我们从几个类型开始:

coerce (+) :: (Num n, Coercible (n -> n -> n) b) => b
myf :: F c d
Run Code Online (Sandbox Code Playgroud)

第一个问题是GHC没有希望固定下来n所以它可以选择实施(+).

让我们看看如果我们使用范围类型变量来尝试一个简单的解决方案会发生什么:

myzip :: forall a b . Num b => F a b -> F a b
myzip = coerce ((+) :: b -> b -> b) myf
Run Code Online (Sandbox Code Playgroud)

这是不被接受的.为什么?因为这种类型myf很暧昧!如果我们myzip用另一个论点展开,我们可以更清楚地看到这一点:

myzip x = coerce ((+) :: b -> b -> b) myf x
Run Code Online (Sandbox Code Playgroud)

Coercible使用类型构造函数的方式(->在这种情况下),我们可以排列所有内容并得出结论,类型myf必须是可强制的b,其中x :: F a b.但myf在这种情况下的类型是模糊的.因此GHC有没有办法来选择合适的Coercible之间的实例b和类型myf.因为coerce真的是引擎盖下的标识函数,选择哪一个并不重要,但GHC根本不会选择基于模糊类型变量的实例.为了使这项工作,您需要类似的东西

myzip :: forall a b . Num b => F a b -> F a b
myzip = (coerce ((+) :: b -> b -> b)) (myf :: F a b)
Run Code Online (Sandbox Code Playgroud)

输入角色

类型角色不能(至少目前)以任何方式引导实例解析.他们所能做的只是确定生成什么Coercible实例.特定

class c => X d
Run Code Online (Sandbox Code Playgroud)

GHC会得出这样的结论X d需要c.但是给了

instance c => X d
Run Code Online (Sandbox Code Playgroud)

GHC将不会得出这样的结论X d需要c.我不确定原因的细节,但情况一直如此.