5

在尝试使用Data.Has时,我一直在编写如下代码:

data Name = Name; type instance TypeOf Name = Text
type NameRecord = FieldOf Name;

我发现:

instance I NameRecord where
  ...

抛出编译错误,即:

非法类型同义词族应用实例

然而:

instance (NameRecord ~ a) => I a where
  ...

编译良好。

我认为该错误与 GHC 中的这张票有关,标记为无效。

对票的回复说:

我不确定你在暗示什么。我们不能自动转换

instance C (Fam Int) -- (1)

进入

instance (Fam Int ~ famint) => C famint -- (2)

如果只有一个实例,这会起作用,但是一旦有两个这样的实例,它们总是重叠的。

也许您建议我们无论如何都应该这样做,程序员应该只考虑隐式转换。我不认为这是一个好主意。令人困惑的好处很少(因为您总是可以毫不费力地自己编写转换后的实例)。

有人可以详细说明这个解释,也许有一些示例代码,其中(1)失败但(2)没有,为什么?

4

1 回答 1

4

(1)失败但(2)没有的情况是微不足道的;type ExampleOfATypeSynonym = ...因为在实例声明中不允许使用类型同义词 ( ),但在约束中允许使用同义词,所以在任何只有一个实例的情况下,如下所示:

-- (1)
class Foo a
type Bla = ()
instance Foo Bla

...可以转化为:

-- (2)
class Foo a
type Bla = ()
instance (a ~ Bla) => Foo a

(1) 失败的唯一原因是实例声明中不允许使用类型同义词,这是因为类型同义词就像类型函数:它们提供从类型名称到类型名称的单向映射,所以如果你有一个type B = A和 a instance Foo B,不明显的Foo A是创建了一个 的实例。该规则存在,因此您必须改为编写instance Foo A以明确这实际获取实例的类型。

在这种情况下,类型族的使用是无关紧要的,因为问题在于您使用的是类型同义词,即NameRecord类型。您还必须记住,如果类型同义词被删除并FieldOf Name直接替换为,编译仍然会失败;那是因为“类型族”只是类型同义词的增强版本,因此在这种情况下FieldOf Name也是“类型同义词” 。Name :> Text您必须使用数据系列和数据实例来获得“双向”关联。

有关数据系列的更多信息,请参阅GHC 文档


我认为您的意思是“......其中(2)失败但(1)没有......”

假设我们有一个像这样的类型类:

class Foo a where
  foo :: a

现在,您可以像这样编写实例:

 instance Foo Int where
   foo = 0

 instance Foo Float where
   foo = 0

 main :: IO ()
 main = print (foo :: Float)

这正如人们所期望的那样工作。但是,如果您将代码转换为:

{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
class Foo a where
  foo :: a

instance (a ~ Int) => Foo a where
  foo = 0

instance (a ~ Float) => Foo a where
  foo = 0

main :: IO ()
main = print (foo :: Float)

它不编译;它显示错误:

test.hs:5:10:
    Duplicate instance declarations:
      instance a ~ Int => Foo a -- Defined at test.hs:5:10-27
      instance a ~ Float => Foo a -- Defined at test.hs:8:10-29

因此,这就是您希望寻找的示例。现在,只有在有多个实例Foo使用此技巧时才会发生这种情况。这是为什么?

GHC 解析类型类时,只看实例声明头;即它忽略=>. 当它选择了一个实例时,它“提交”给它,并检查 之前的约束=>以查看它们是否为真。所以,起初它看到两个实例:

instance Foo a where ...
instance Foo a where ...

仅根据这些信息显然不可能决定使用哪个实例。

于 2012-05-07T11:52:29.103 回答