2010-04-07 99 views
9

此代码编译罚款:问题混合型类和类型的家庭时

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, 
    UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables, 
    TypeOperators, TypeSynonymInstances, TypeFamilies #-} 
class Sel a s b where 
    type Res a s b :: * 

instance Sel a s b where 
    type Res a s b = (s -> (b,s)) 

instance Sel a s (b->(c,a)) where 
    type Res a s (b->(c,a)) = (b -> s -> (c,s)) 

,但只要我添加将R谓词GHC失败:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, 
    UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables, 
    TypeOperators, TypeSynonymInstances, TypeFamilies #-} 
class Sel a s b where 
    type Res a s b :: * 

instance Sel a s b where 
    type Res a s b = (s -> (b,s)) 

class R a where 
    type Rec a :: * 
    cons :: a -> Rec a 
    elim :: Rec a -> a 
instance Sel a s (b->(c,Rec a)) where 
    type Res a s (b->(c,Rec a)) = (b -> s -> (c,s)) 

抱怨说:

Illegal type synonym family application in instance: 
     b -> (c, Rec a) 
    In the instance declaration for `Sel a s (b -> (c, Rec a))' 

这是什么意思和(最重要的是)我该如何解决它?

由于

+2

没有第一段代码不适合我编译。 GHC(6.12.1)抱怨'冲突的家庭实例声明'。 – kennytm 2010-04-07 06:49:10

回答

12

类型系列是单向的:您可以将Rec a扩展为其计算类型,但不能(唯一地)从扩展回到Rec a。这使得类型函数的应用程序不适合实例签名,因为它们永远不会触发实例应用。

你可以尝试,而不是:

instance Rec a ~ reca => Sel a s (b->(c,reca)) 

这意味着别的东西:它说,任何功能b -> (c, reca)是一个实例,然后当它已经无可挽回地匹配,编译器会检查Rec a ~ reca。但是这可能足以满足你的需求。

1

Rec不是类型构造函数;这是一个类型函数。也许你只能在类型定义的类型中使用它,而不能在类声明中使用它?我在这里疯狂猜测;我不明白类型家族的所有规则。

我不知道如何解决它,但是有些事情尝试包括:

  • 摆脱阶级SEL的,只是定义type family Res a s b :: *。使用type instance而不是类机制。

  • 使用data制作类型Rec内射几乎是不可能的,但我不这么认为。

  • 减少到可以工作的最小数量的语言扩展—它可以使其他人更容易帮助您,它也可以帮助编译器。

+1

切换到使用'data'将会起作用 - 实例头部允许数据族,而类型同义词族不允许。 – 2010-04-07 06:56:41

1

这意味着在声明类型实例时不允许使用类型synomym族。请参阅GHC手册的"Type families and instance declarations"部分。

你可以修复它的唯一方法是重构,以便不需要它。