質問

(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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top