[Haskell-beginners] Problems inferring instances

dcmorse+haskell at gmail.com dcmorse+haskell at gmail.com
Mon Jan 5 21:40:36 EST 2009

Learning from the example of "read" and also Real World Haskell, I
come across the idea to overload my function's return types. Trying to
think of an application for this, I've always wanted to write ==
applications like in Icon, that is

a === b === c means a == b && b == c.

This requires === to sense what context it is called in. If it's being
called for a Boolean value, it needs to return a Boolean value. If
it's being called as a parameter to another === application, then it
needs to somehow remember both it's truthiness and if true what value
its already seen.

The idea is to eventually expand this to be able to write

a >== b >== c

...but one thing at a time!

My plan of attack is to write a typeclass:
class Chain a b c where
 (==) :: a -> b -> c
First check: Turned on -fglasgowexts to allow multiple parameters to

Then write instances for the various contexts in which == might be
applied. For boolean return values there are three instances:

instance Eq a => Chain a a Bool ...
 example: 5 == 4
instance Eq a => Chain (Valid a) a Bool
 example:  rightmost == in (5==4)==3
instance Eq a => Chain a (Valid a) Bool
 example: leftmost == in 5==(4==3)

 Sidebar: Valid is just an imitation of Maybe:
 data Valid a = Value a | Fail deriving (Show)

But back to ==, the interesting part is the times when one senses
we're in a context of comparing more values, for example, the left ==
in (x==y)==z.

instance Eq a => Chain a a (Valid a)
instance Eq a => Chain (Valid a) a (Valid a)
instance Eq a => Chain a (Valid a) (Valid a)

To test out this implementation I write a test function:
test2 :: Eq a => a -> a -> Bool
test2 a b = a === b
and this works as expected.

The problem comes when chainging the ===s together, I have to
spoon-feed the compiler the inferred type:

-- compiling this causes an error
test3choke :: Eq a => a -> a -> a -> Bool
test3choke a b c = a === b === c

The error text:

 [1 of 1] Compiling ME               ( ME.hs, interpreted )

     Could not deduce (Chain a a c) from the context (Eq a)
       arising from use of `===' at ME.hs:63:19-25
     Possible fix:
       add (Chain a a c) to the type signature(s) for `test3choke'
     In the first argument of `(===)', namely `a === b'
     In the expression: (a === b) === c
     In the definition of `test3choke':
         test3choke a b c = (a === b) === c

     Could not deduce (Chain c a Bool) from the context (Eq a)
       arising from use of `===' at ME.hs:63:19-31
     Possible fix:
       add (Chain c a Bool) to the type signature(s) for `test3choke'
       or add an instance declaration for (Chain c a Bool)
     In the expression: (a === b) === c
     In the definition of `test3choke':
         test3choke a b c = (a === b) === c
 Failed, modules loaded: none.

-- but spoon-feeding it the types will work
test3Int  :: Int -> Int -> Int -> Bool
test3Int  a b c = ((a === b) :: Valid Int) === c

So it seems that the compiler is not doing instance inference the same
way it does type inference. This is frustrating because the output of
the parenthesiszed a === b can only be either of type Bool or Valid a,
and the second argument of the outer === has to have the same type,
which will force it to Valid a in most cases (Bool being an
interesting exception).

Is there some way to goad the compiler forward on this one, or is this
the wrong approach altogether?

Attachment: http://www.osaurus.us/~dm/tmp/ME.hs

More information about the Beginners mailing list