Haskell类型类和类型族(续)

时间:2010-04-08 07:17:46

标签: haskell typeclass

我需要一些帮助来计算编译器错误,这真的让我疯狂......

我有以下类型类:

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 个答案:

答案 0 :(得分:4)

写作时

instance Selectable a s b where

您说任何类型组合都是可选择的实例。这为其他实例留下了空间。

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

您是否可以使您的第一个实例更具体,以便它不再与您尝试编写的其他实例冲突?

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

答案 1 :(得分: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 ...

这可能会导致您在呼叫站点出现问题,但使用两个名称不同的函数可能要好得多。