1

(コメントを使用すると、コピーと貼り付けが簡単になります)

--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)

「正しいこと」を行うこの種のクラスを書くことは可能ですか? つまり、正しいインスタンスが選択されるようにプログラムを変更するにはどうすればよいでしょうか。

ランタイム ソリューションを 1 つ知っていると思いますが、それはあまり良くありません。

書き換えルールを見てきましたが、それは良い解決策ですか?

4

1 に答える 1

3

この場合、コンパイラが適切なインスタンスを選択するよりも具体的であるためOverlappingInstances、プラグマを使用できます。Box (a,a)Box (a,b)

非公式に言うと、は にインスタンス化できる場合aよりも具体的です。別の定義は、統一して が得られる場合です。たとえば、 inに=を入れることができるので、より具体的です。bbaaba(a,b)ba(a,a)(a,b)

コンパイラが最も具体的なインスタンスを見つけられない場合、OverlappingInstances.

于 2013-08-27T13:46:23.520 に答える