[Haskell-cafe] Instances that shouldn't overlap

Paul Johnson paul at cogito.org.uk
Wed Nov 26 15:05:40 EST 2008


I'm trying to set up some operators for applicative versions of prelude 
types.  For instance:

-- | Applicative Equality.
class (Eq a) => AppEq f a where
   (.==.), (./=.) :: f a -> f a -> f Bool

instance (Applicative f, Eq a) => AppEq f a where
   (.==.)  = liftA2 (==)
   (./=.)  = liftA2 (/=)

Hopefully the intention is fairly straightforward: if "f" is an instance 
of Applicative then the lifted implementation of the underlying type.  
Otherwise I can just give my own instance, which is useful for things 
that "wrap" prelude types but where "fmap" doesn't work.  For instance:

data (Ord a) => Interval a = Interval a a

instance (Ord a) => AppEq Interval a where
   i1@(Interval _ u1) .==. i2@(Interval _ u2)
       | isSingleton i1 && isSingleton i2 && u1 == u2  = Interval True True
       | has i1 u2 || has i2 u1                        = Interval False True
       | otherwise                                     = Interval False 
   i1 ./=. i2 = let Interval b1 b2 = (i1 .==. i2) in Interval (not b2) 
(not b1)

isSingleton :: (Ord a) => Interval a -> Bool
isSingleton (Interval lower upper) = lower == upper

has :: (Ord a) => Interval a -> a -> Bool
has (Interval lower upper) v = v >= lower && v <= upper

You can't (easily) define fmap for Interval because the function given 
as an argument might not be monotonic.  So instead you have to write 
custom implementations for each lifted function, as shown here for 
(.==.) and (./=.) .  The same principle works for AppOrd, AppNum etc, 
but I'm trying to solve the problem for just AppEq for now.

This compiles, but when I try to use it I get this in ghci:

*Interval> let i1 = Interval 4 5
*Interval> let i2 = Interval 4 6
*Interval> i1 .==. i2

    Overlapping instances for AppEq Interval Integer
      arising from a use of `.==.' at <interactive>:1:0-9
    Matching instances:
      instance (Ord a) => AppEq Interval a
        -- Defined at Interval.hs:(22,0)-(27,78)
      instance (Control.Applicative.Applicative f, Eq a) => AppEq f a
        -- Defined at AppPrelude.hs:(32,0)-(34,23)
    In the expression: i1 .==. i2
    In the definition of `it': it = i1 .==. i2

I'm puzzled, because Interval is not an instance of Applicative, so the 
second instance doesn't apply.  Can anyone help me out?

I'm using ghc 6.8.3, so its possible that this was a bug fixed in 6.10.


More information about the Haskell-Cafe mailing list