开发者

Haskell type classes and type families (cont'd)

I need some help in figuring a compiler error which is really driving me nuts...

I have the following type class:

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

which I instance twice. First time goes like a charm:

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'')))   

since the type checker infers

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

and this signature matches with the class signature for (-->) since

Res a s b = Reference s b

Now I add a second instance and everything breaks:

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

the compiler complains that

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

reading carefully the compiler is telling me that it has inferred the type of (-->) thusly:

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

which is correct since

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

but why can't it match the two definitions?

Sorry for not offering a more succint and standalone example, but in this case I cannot figure how to do it...


When you write

instance Selectable a s b where

you are saying that any combination of types is an instance of Selectable. This leaves no room for other instances.

Sure, certain shady compiler extensions will allow you to write more (necessarily conflicting) instances, but you are bound to run into trouble.

Can you make your first instance more specific so it no longer conflicts with the other instance you are trying to write?

Running into problems like these is usually a sign that type classes are not the answer. If you're writing only two instances, why not give up overloading and just write two specific functions—one for each use case?


Like I said elsewhere, I have no idea what's going on in the second instance given so little context. However, maybe you can make your instances nonoverlapping by doing this instead:

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 ...

This is likely to cause you problems at the call sites instead, though, and it's probably much better to use two functions with different names.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜