具有类型族的模糊类型
Ambiguous type with type families
我 运行 遇到了 GHC 无法匹配 Foo t
和 Foo t0
的问题,在我看来它肯定像 t ~ t0
。这是一个最小的例子:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
data Foobar :: * -> * where
Foobar :: Foo t -> Foobar t
type family Foo a :: *
class Bar t where
f :: Foobar t
g :: Foo t
-- f = Foobar g
取消注释最后一行时,GHC 抱怨:
Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
Relevant bindings include f :: Foobar t (bound at test.hs:13:3)
In the first argument of ‘Foobar’, namely ‘g’
In the expression: Foobar g
我知道 Foo
不是单射的,但根据我的分析,GHC 从未被要求从 Foo t
中得出 t
。似乎t
类型在Foobar g
中丢失了,所以它不能匹配初始的Foo t
和新的Foo t0
。这里的上下文还不够吗?我是否遗漏了 f = Foobar g
无法产生正确结果的情况?
感谢任何帮助!
N.B.: ScopedTypeVariables
和显式类型签名似乎没有帮助。添加约束 a ~ Foo t
并使用 a
代替 Foobar g
中的 g
类型也不起作用。
看起来很像:ambiguous type error when using type families, and STV is not helping。我考虑过使用 Proxy
,但我觉得在这种情况下 GHC 应该能够弄清楚。
I understand that Foo
is not injective, but from my analysis GHC is never asked to come up with t
from Foo t
.
所以,你意识到了歧义。让我们明确一点:
type instance Foo () = Bool
type instance Foo Char = Bool
instance Bar () where
-- I omit the declaration for f
g = True
instance Bar Char where
g = False
main = print (g :: Bool)
您在f = Foobar g
中的问题与歧义有关。
关键在于:f = Foobar g
的定义并不意味着 g
与 f
在同一实例中被选中。它可以引用不同的实例!
考虑
show (x,y) = "(" ++ show x ++ ", " ++ show y ++ ")"
上面,show
的 RHS 使用与 LHS show
所在的实例不同。
在您的 f = Foobar g
行中,GHC 推断 g :: Foo t
其中 t
与 f
实例的索引相同。但是,这还不足以 select g
的实例!事实上,我们可能对其他 t0
有 Foo t ~ Foo t0
,因此 g
可能引用 t0
实例中的 g
,导致歧义错误。
请注意,即使最后一行被注释掉,您的代码也会被 GHC 8 拒绝,因为 g
的类型本质上是不明确的:
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
• In the ambiguity check for ‘g’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: g :: forall t. Bar t => Foo t
In the class declaration for ‘Bar’
我们可以按照建议让 GHC 8 更宽松,就像 GHC 7 一样。这将检查您的代码类型,直到我们取消注释最后一行。
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
这与您在 GHC 7 中看到的错误相同。
在 GHC 8 中,我们有另一种奢侈:我们可以 明确地 选择 t
为 g
如下:
class Bar t where
f :: Foobar t
f = Foobar (g @ t)
g :: Foo t
当然,这需要打开更多的扩展程序。在 GHC 7 中,您需要一个代理才能明确 select 一个实例。
我 运行 遇到了 GHC 无法匹配 Foo t
和 Foo t0
的问题,在我看来它肯定像 t ~ t0
。这是一个最小的例子:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
data Foobar :: * -> * where
Foobar :: Foo t -> Foobar t
type family Foo a :: *
class Bar t where
f :: Foobar t
g :: Foo t
-- f = Foobar g
取消注释最后一行时,GHC 抱怨:
Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
Relevant bindings include f :: Foobar t (bound at test.hs:13:3)
In the first argument of ‘Foobar’, namely ‘g’
In the expression: Foobar g
我知道 Foo
不是单射的,但根据我的分析,GHC 从未被要求从 Foo t
中得出 t
。似乎t
类型在Foobar g
中丢失了,所以它不能匹配初始的Foo t
和新的Foo t0
。这里的上下文还不够吗?我是否遗漏了 f = Foobar g
无法产生正确结果的情况?
感谢任何帮助!
N.B.: ScopedTypeVariables
和显式类型签名似乎没有帮助。添加约束 a ~ Foo t
并使用 a
代替 Foobar g
中的 g
类型也不起作用。
看起来很像:ambiguous type error when using type families, and STV is not helping。我考虑过使用 Proxy
,但我觉得在这种情况下 GHC 应该能够弄清楚。
I understand that
Foo
is not injective, but from my analysis GHC is never asked to come up witht
fromFoo t
.
所以,你意识到了歧义。让我们明确一点:
type instance Foo () = Bool
type instance Foo Char = Bool
instance Bar () where
-- I omit the declaration for f
g = True
instance Bar Char where
g = False
main = print (g :: Bool)
您在f = Foobar g
中的问题与歧义有关。
关键在于:f = Foobar g
的定义并不意味着 g
与 f
在同一实例中被选中。它可以引用不同的实例!
考虑
show (x,y) = "(" ++ show x ++ ", " ++ show y ++ ")"
上面,show
的 RHS 使用与 LHS show
所在的实例不同。
在您的 f = Foobar g
行中,GHC 推断 g :: Foo t
其中 t
与 f
实例的索引相同。但是,这还不足以 select g
的实例!事实上,我们可能对其他 t0
有 Foo t ~ Foo t0
,因此 g
可能引用 t0
实例中的 g
,导致歧义错误。
请注意,即使最后一行被注释掉,您的代码也会被 GHC 8 拒绝,因为 g
的类型本质上是不明确的:
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
• In the ambiguity check for ‘g’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: g :: forall t. Bar t => Foo t
In the class declaration for ‘Bar’
我们可以按照建议让 GHC 8 更宽松,就像 GHC 7 一样。这将检查您的代码类型,直到我们取消注释最后一行。
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
这与您在 GHC 7 中看到的错误相同。
在 GHC 8 中,我们有另一种奢侈:我们可以 明确地 选择 t
为 g
如下:
class Bar t where
f :: Foobar t
f = Foobar (g @ t)
g :: Foo t
当然,这需要打开更多的扩展程序。在 GHC 7 中,您需要一个代理才能明确 select 一个实例。