[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
typeclasses.
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 )
ME.hs:63:19:
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
ME.hs:63:19:
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