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

标签 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 提示它无法将类型“a0”的表示与“Int”的表示相匹配。基本上,coerce (+) 的类型是 F a0 -> F a -> F a,而不是我想要的类型,即 F a -> F a -> F a.

考虑到a当前的phantom角色,这是合理的。我想知道是否有一种简单的方法可以通过其他方法进行类型推断(我不想写出签名,这就是我首先使用 coerce 的原因!) 。 特别是,我期望如果我将参数 a 的作用限制为名义值,那么 GHC 将能够知道签名的唯一可能选择就是我想要的。没有这样的运气:GHC 给出了同样的错误。

如果重要的话,在我的实际代码中,a 的角色必须至少是代表性的,而 b 必须是名义性的。

最佳答案

让我们首先看看几种类型:

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 的结论。我不确定具体原因,但情况一直如此。

关于haskell - 使用名义角色进行类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32596138/

相关文章:

haskell - 来自行为的元素(功能响应式(Reactive)编程)

haskell - 什么时候unsafeInterleaveIO不安全?

haskell - 为什么 Haskell 可以在这个函数中推导出 [] 类型

haskell - 将 Read 实例添加到 Path to Path 包

haskell - 在 GHCi 中键入家庭恶作剧

haskell - 你如何在 Notepad++ 上编译和运行haskell

haskell - 如何编译BNF转换器?

haskell - GHC 说 "digits"需要一个 Int,当它需要一个 Integral 时

haskell - 应用仿函数分析

c++ - 如何从 C++ 管理 ghci?