2012-05-07 52 views
5

在尝试使用Data.Has,我已经写了如下代码:哈斯克尔类型的家庭,认识错误消息

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

我发现:

instance I NameRecord where 
    ... 

抛出一个编译错误,即:

Illegal type synonym family application in instance

鉴于:

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

编译好。

我相信这个错误与GHC中的this票有关,标记为无效。

售票的回应说:

I am not sure what you are suggesting. We cannot automatically transform

instance C (Fam Int) -- (1) 

into

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

This works if there is only one instance, but as soon as there are two such instances, they always overlap.

Maybe you are suggesting that we should do it anyway and programmers should just take the implicit transformation into account. I don't think that this is a good idea. It's confusing for very little benefit (as you can always write the transformed instance yourself with little effort).

谁能细说了解释,或许与一些示例代码,其中(1)失败,但(2)没有,为什么?

回答

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和一个instance Foo B,但不明显的是创建了Foo A的实例。该规则存在,因此您必须编写instance Foo A来代替,以明确是实际获取实例的类型。

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

有关数据族的更多信息可在GHC documentation中找到。我想你的意思是“...哪里(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 ... 

根据这个信息单独决定使用哪个实例显然是不可能的。

+0

出于兴趣,您是否碰巧知道GHC的解析类型类的方法是否是明确的设计决策?如果是这样,原因呢? (或者也许这个选择太复杂了,不能很好地实现?) – huon

+3

其原因是Haskell报告要求它的行为如此。 **认为**的原因是,如果它不是这样的行为,那么就必须有一种算法给出了“类型适合约束的好坏程度”的启发式算法;你必须争辩说:“是的,这种类型适合这个类的实例,但是这个类实例更适合,因为{约束更少,缩短的距离更短,......}。”开发这样的启发式可能是可能的,但它会打破开放世界假设,这是类型类的一个关键概念。 – dflemstr

+0

想象一下'instance String〜a => Foo a'和'instance a〜[b] => Foo a'。这是一个你需要一个算法来解析'Foo [Char]'的例子。 – dflemstr