Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Could not deduce ... from the Context error

Tags:

haskell

I have type classes, for all of which I would like to have some common behavior. My problem is explained in the following code:

class A a
class B b

class X x where
    method :: (A a, B b) =>  x -> a -> b

data T = L | M | N
data U = P | Q | R

instance A T
instance B U

data Y = ZZZ

instance X Y where
    method _ L = P
    method _ M = Q
    method _ N = R

When I load this module, I get the following error:

example.hs:19:14:
    Could not deduce (a ~ T)
    from the context (A a, B b)
      bound by the type signature for method :: (A a, B b) => Y -> a -> b
      at example.hs:(17,5)-(19,18)
      `a' is a rigid type variable bound by
          the type signature for method :: (A a, B b) => Y -> a -> b
          at example.hs:17:5
    In the pattern: N
    In an equation for `method': method _ N = R
    In the instance declaration for `X Y'

example.hs:19:18:
    Could not deduce (b ~ U)
    from the context (A a, B b)
      bound by the type signature for method :: (A a, B b) => Y -> a -> b
      at example.hs:(17,5)-(19,18)
      `b' is a rigid type variable bound by
          the type signature for method :: (A a, B b) => Y -> a -> b
          at example.hs:17:5
    In the expression: R
    In an equation for `method': method _ N = R
    In the instance declaration for `X Y'
Failed, modules loaded: none.

I am at loss what to do in this case. Even when T and U are instance of A and B, I get this error. If I cannot return a rigid type value from method, how do I code this part?

like image 807
mutelogan Avatar asked Feb 19 '12 21:02

mutelogan


1 Answers

The signature method :: (A a, B b) => x -> a -> b promises that method works for every pair of types (a, b) with a an instance of A and b an instance of B, but you define it to work only with two specific types.

This is fundamentally different from interfaces in Java or the like, where the callee chooses which type is used, the only thing the caller knows is that interface X is implemented. In Haskell, given such a signature, the caller decides which types are used (here, what type is passed as second argument and what type shall be returned) and the callee has to be able to provide the demanded functionality (as long as the demanded types are instances of the required classes).

Without any methods in classes A and B to analyse respectively construct values of an instance of that class, you cannot implement method other than with undefined (various degrees of undefinedness are possible due to seq), so you would have to tell the world that you are in fact using T and U.

Another way is to make X a multiparameter type class,

{-# LANGUAGE MultiParamTypeClasses #-}

class (A a, B b) => X x a b where
    method :: x -> a -> b

However, that might require functional dependencies to resolve instances. Another way would be to use associated types,

{-# LANGUAGE TypeFamilies #-}

class X x where
    type AType x
    type BType x
    method :: x -> AType x -> BType x

instance X Y where
    type AType Y = T
    type BType Y = U
    method ...
like image 159
Daniel Fischer Avatar answered Sep 20 '22 00:09

Daniel Fischer