2010-04-08 44 views
2

我需要搞清楚一个编译错误这是真正推动我坚果一些帮助......Haskell的类型类和类型的家庭(续)

我有以下类型的类:

infixl 7 --> 
class Selectable a s b where 
    type Res a s b :: * 
    (-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> Res a s b 

我实例两次。第一次是这样一个魅力:

instance Selectable a s b where 
    type Res a s b = Reference s b 
    (-->) (Reference get set) (_,read,write) = 
     (Reference (\s -> 
         let (v,s') = get s 
         in (read v,s')) 
        (\s -> \x -> 
         let (v,s') = get s 
          v' = write v x 
          (_,s'') = set s' v' 
         in (x,s''))) 

因为类型检查推断

(-->) :: Reference s a -> (n,a->b,a->b->a) -> Reference s b 

与此签名与类签名匹配( - >),因为

Res a s b = Reference s b 

现在我添加第二个实例并且所有内容都会中断:

instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) where 
    type Res a s (Method reca b c) = b -> Reference s c 
    (-->) (Reference get set) (_,read,write) = 
    \(x :: b) -> 
     from_constant(Constant(\(s :: s)-> 
          let (v,s') = get s :: (a,s) 
           m = read v 
           ry = m x :: Reference (reca) c 
           (y,v') = getter ry (cons v) :: (c,reca) 
           v'' = elim v' 
           (_,s'') = set s' v'' 
           in (y,s''))) :: Reference s c 

编译器抱怨

Couldn't match expected type `Res a s (Method reca b c)' 
     against inferred type `b -> Reference s c' 
The lambda expression `\ (x :: b) -> ...' has one argument, 
which does not match its type 
In the expression: 
    \ (x :: b) 
     -> from_constant (Constant (\ (s :: s) -> let ... in ...)) :: 
      Reference s c 
In the definition of `-->': 
    --> (Reference get set) (_, read, write) 
      = \ (x :: b) 
       -> from_constant (Constant (\ (s :: s) -> ...)) :: Reference s c 

仔细阅读编译器告诉我,它已经推断出的类型( - >)正是如此:

(-->) :: Reference s a -> (n,a->(Method reca b c),a->(Method reca b c)->a) -> (b -> Reference s c) 

这是正确的,因为

Res a s (Method reca b c) = b -> Reference s c 

但为什么它不能匹配这两个定义?

对不起,不提供更succint和独立的例子,但在这种情况下,我想不出该怎么办呢?

+2

你能给出一个完整的可运行示例吗?即从哪里引用?甚至包括'{ - #LANGUAGE TypeFamilies# - }'。这可以帮助别人帮助你。 – yairchu 2010-04-08 09:34:36

+0

这是一个很大的...这只是一个更大的项目,我不可能完整发布:( – 2010-04-08 19:37:35

回答

4

当你写

instance Selectable a s b where 

你是说任何类型的组合是Selectable的一个实例。这为其他实例留下了空间。

当然,某些阴暗的编译器扩展将允许你编写更多(必然冲突)的实例,但是你一定会遇到麻烦。

你可以让你的第一个实例更具体,所以它不再与你试图写的其他实例发生冲突吗?

遇到这样的问题通常是类型类不是答案的标志。如果你只写两个实例,为什么不放弃重载,只写两个特定的函数 - 每个用例一个?

+0

嗯,我现在有两个功能,但因为他们有非常相似的语义重载感觉像正确的方式... 我需要指定的东西,如“如果没有具体匹配发生第二次,然后与第一次”,但我开始担心,这可能是不可行的:( – 2010-04-08 12:02:35

+0

朱塞佩,可能的想法描述在[http://www.haskell.org/haskellwiki/GHC/AdvancedOverlap]为你工作吗?它似乎很好地描述你的情况! – yatima2975 2010-04-08 15:08:57

+0

是否有可能让他把不那么通用的定义第一,然后其他作为'后备'的情况? – jakebman 2010-04-08 18:11:26

0

就像我在其他地方所说的那样,我不知道在第二个例子中发生了什么,因为它的背景很少。但是,也许你可以让你的情况不重叠做这个:

class Selectable a s b r where 
    (-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> r 

instance Selectable a s b (Reference s b) where ... 
instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) (b -> Reference s c) where ... 

这可能导致你在调用点问题,而不是,虽然,这可能是更好的使用两种功能不同的名称。