为什么 GHC 不能在 Rank 2 类型的 class 类型族上推断出类型相等?
Why can't GHC deduce type equality on a class type family in a Rank 2 type?
作为我正在经历的一个非常精简的版本:
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
class ValueGen v where
type Output v
generate :: v -> Output v
instance ValueGen Integer where
type Output (Integer) = Integer
generate n = n + 1
newtype IntGenerator = Gen { generator :: forall v. ValueGen v => ((Output v) ~ Integer) => v }
myGen :: IntGenerator
myGen = Gen (3 :: Integer)
GHC给出的错误是
Could not deduce: v ~ Integer
from the context: (ValueGen v, Output v ~ Integer)
bound by a type expected by the context:
forall v. (ValueGen v, Output v ~ Integer) => v
如果我只是尝试通过类型相等性来限制 v
,这很好用。
GHC 遇到了什么问题?如果已经通过输入 3 :: Integer
通知了限制,为什么还要尝试推断限制 v ~ Integer
?限制检查不应该是Output Integer
解析为Integer
等于Integer
然后pass吗?
摘要
我试图编写一个 2 级类型,其中包含两个 Pipeline
class 实例,它们共享一些中间类型。基本想法是获得两条管道,例如
a|---|b b|---|c
并生成一个新类型 Joined
然后它是 Pipeline
的一个实例
a|------------|c
a|---|b b|---|c
问题是内部管道与内部 forall
一起存储,使用类型等于 Joined
类型参数的限制 - 但 GHC 似乎无法识别何时满足限制.
您所写的定义意味着 IntGenorator
您有:
If you give me an IntGenorator
and think of some type v
such that Output v ~ Integer
then I will give you something of type v
based on whatever is inside the IntGenorator
If for any type v
such that Output v ~ Integer
, you can give me something of type v
then you can construct something of type IntGenorator
因为类型族不是单射的,所以可能有其他类型 v
而不是 Integer
这样 Output v ~ Integer
(注意它们可能在 ghc 尚未编译的模块中或者还没有写)。因此 ghc 无法证明 v
与 Output v ~ Integer
的唯一类型是 Integer
(或者更确切地说是实现 Num
的一些类型集)因此 3 :: Integer
(或者而 3 :: Num a => a
) 是 forall v. (Output v ~ Integer) => v
.
类型的有效值
例如如果有人用 Output Char = Integer
添加了实例 ValueGen Char
怎么办?那么 3
肯定不是 Char
类型(除非有人实现 Num Char
)所以你不能把它放在 IntGenerator
中
作为我正在经历的一个非常精简的版本:
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
class ValueGen v where
type Output v
generate :: v -> Output v
instance ValueGen Integer where
type Output (Integer) = Integer
generate n = n + 1
newtype IntGenerator = Gen { generator :: forall v. ValueGen v => ((Output v) ~ Integer) => v }
myGen :: IntGenerator
myGen = Gen (3 :: Integer)
GHC给出的错误是
Could not deduce: v ~ Integer
from the context: (ValueGen v, Output v ~ Integer)
bound by a type expected by the context:
forall v. (ValueGen v, Output v ~ Integer) => v
如果我只是尝试通过类型相等性来限制 v
,这很好用。
GHC 遇到了什么问题?如果已经通过输入 3 :: Integer
通知了限制,为什么还要尝试推断限制 v ~ Integer
?限制检查不应该是Output Integer
解析为Integer
等于Integer
然后pass吗?
摘要
我试图编写一个 2 级类型,其中包含两个 Pipeline
class 实例,它们共享一些中间类型。基本想法是获得两条管道,例如
a|---|b b|---|c
并生成一个新类型 Joined
然后它是 Pipeline
a|------------|c
a|---|b b|---|c
问题是内部管道与内部 forall
一起存储,使用类型等于 Joined
类型参数的限制 - 但 GHC 似乎无法识别何时满足限制.
您所写的定义意味着 IntGenorator
您有:
If you give me an
IntGenorator
and think of some typev
such thatOutput v ~ Integer
then I will give you something of typev
based on whatever is inside theIntGenorator
If for any type
v
such thatOutput v ~ Integer
, you can give me something of typev
then you can construct something of typeIntGenorator
因为类型族不是单射的,所以可能有其他类型 v
而不是 Integer
这样 Output v ~ Integer
(注意它们可能在 ghc 尚未编译的模块中或者还没有写)。因此 ghc 无法证明 v
与 Output v ~ Integer
的唯一类型是 Integer
(或者更确切地说是实现 Num
的一些类型集)因此 3 :: Integer
(或者而 3 :: Num a => a
) 是 forall v. (Output v ~ Integer) => v
.
例如如果有人用 Output Char = Integer
添加了实例 ValueGen Char
怎么办?那么 3
肯定不是 Char
类型(除非有人实现 Num Char
)所以你不能把它放在 IntGenerator