Reputation: 1598
(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?
Upvotes: 1
Views: 158
Reputation: 11208
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
.
Upvotes: 3