(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
OverlappingInstances
pragma in this case asBox (a,a)
is more specific thanBox (a,b)
so compiler will choose the right instance for you.Informally, you say
a
is more specific thanb
if you can instantiateb
toa
. Another definition can be, if you unifya
andb
you 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
.