【问题标题】:Using Nominal Roles for Type Inference使用名义角色进行类型推断
【发布时间】:2015-12-12 07:18:32
【问题描述】:

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

【问题讨论】:

    标签: haskell ghc


    【解决方案1】:

    让我们从几种类型开始:

    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 的类型必须与b 强制转换,其中x :: F a b。但是在这种情况下myf 的类型是模棱两可的。因此,GHC 无法在bmyf 的类型之间选择适当的Coercible 实例。因为coerce 确实是底层的标识函数,所以选择哪一个并不重要,但GHC 根本不会根据不明确的类型变量来选择实例。要完成这项工作,您需要类似的东西

    myzip :: forall a b . Num b => F a b -> F a b
    myzip = (coerce ((+) :: b -> b -> b)) (myf :: F a b)
    

    键入角色

    类型角色不能(至少目前)以任何方式指导实例解析。他们所能做的就是确定生成了哪些Coercible 实例。给定

    class c => X d
    

    GHC 将得出结论,X d 包含c。但是给定

    instance c => X d
    

    GHC不会断定X d 必然包含c。我不确定具体原因,但一直都是这样。

    【讨论】:

    • 确实,将( ::Int->Int->Int) 加到原代码的(+) 后,其余部分就可以正常编译了。
    • 我的例子似乎过于简单了——我很抱歉。我用一个示例更新了我的帖子,其中将类型 :: b -> b -> b 添加到 (+)(以及 -XScopedTypeVars 和一个明确的 forall)并不能解决问题。
    • 感谢您更新您的答案,以及您的明确解释!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-13
    • 2022-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多