(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 as Box (a,a)
is more specific than Box (a,b)
so compiler will choose the right instance for you.
Informally, you say a
is more specific than b
if you can instantiate b
to a
. Another definition can be, if you unify a
and b
you get a
. For example, in (a,b)
you can put b
=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
.