(Using comments for easier copy and pasting)
--Say I have the following monad:
{-# LANGUAGE GADTs, FlexibleInstances #-}
data Instruction b where
Write :: a -> Instruction ()
Write2 :: (a,a) -> Instruction ()
Read :: Instruction a
Read2 :: Instruction (a,a)
Bind :: Instruction a -> (a -> Instruction b) -> Instruction b
Return :: a -> Instruction a
instance Monad Instruction where
(>>=) = Bind
return = Return
--And the following class:
class Box a where
write :: a -> Instruction ()
read :: Instruction a
instance Box Int where
write = Write
read = Read
instance Box Float where
write = Write
read = Read
instance (Box a,Box b) => Box (a,b) where
write (a,b) = do
write a
write b
read = do
a <- Read
b <- Read
return (a,b)
instance (Box a) => Box (a,a) where
write = Write2
read = Read2
--Now, this works kind of fine, as long as I do not use the overlap:
test = do
let i = 0 :: Int
let f = 0 :: Float
write (i,f)
--But i get an overlapping instance for the following (understandably):
write (i,i)
Is it possible to write this kind of class that will do the "right thing"? That is, how do I change the program such that the right instance is chosen.
I think I know of one runtime solution, but that won't be as nice.
I've seen rewrite rules, is that a good solution?
You can use
OverlappingInstancespragma in this case asBox (a,a)is more specific thanBox (a,b)so compiler will choose the right instance for you.Informally, you say
ais more specific thanbif you can instantiatebtoa. Another definition can be, if you unifyaandbyou geta. For example, in(a,b)you can putb=a, so(a,a)is more specific than(a,b).If compiler can not find the most specific instance it will throw error even with
OverlappingInstances.