类型为

时间:2016-06-13 14:25:19

标签: haskell functional-programming type-families

我遇到了一个GHC无法匹配Foo tFoo 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从未被要求从t提出Foo t。似乎t中的Foobar g类型丢失了,因此它不能与初始Foo t和新Foo t0匹配。这里的背景不够吗?我错过了f = Foobar g无法产生正确结果的情况吗?

任何帮助表示赞赏!

N.B。:ScopedTypeVariables和明确的类型签名似乎没有帮助。在a ~ Foo t中添加约束a并使用g代替Foobar g的类型也不起作用。

看起来很像:ambiguous type error when using type families, and STV is not helping。我考虑使用Proxy,但我觉得在这种情况下GHC应该能够弄明白。

1 个答案:

答案 0 :(得分:7)

  

我理解Foo不是唯一的,但根据我的分析,GHC从未被要求从t提出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其中tf实例的索引相同。但是,这不足以为g选择一个实例!实际上,对于其他Foo t ~ Foo t0,我们可能会t0,因此g可能会引用g实例中的t0,从而导致歧义错误。

请注意,即使最后一行被注释掉,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中,您需要一个代理才能明确地选择实例。