2016-04-28 3 views
6

の重複の解決方法I次のコードもちろんインスタンス

instance {-# OVERLAPS #-} Transformable a a where 
    transform x = x 

instance {-# OVERLAPPABLE #-} (Transformable l l', Transformable r r') 
     => Transformable (Either l r) (Either l' r') 
    where 
    transform = bimap transform transform 

は、それらのインスタンスは、私がEither a bEither a bを変換し、次のように取得しようとしている場合には重複する(変換は、変換に似ている)持っていますエラーメッセージ(ParsingErrorEither something somethingElseの型の別名である)

Overlapping instances for Transformable 
           (parsingerror text) (parsingerror text) 
     arising from a use of ‘makereceipt’ 
    matching instances: 
Matching instances: Overlapping instances for Transformable 
          (ParsingError Text) (ParsingError Text) 
    arising from a use of ‘makeReceipt’ 
Matching instances: 
    instance [overlappable] (Transformable l l', Transformable r r') => 
          Transformable (Either l r) (Either l' r') 
     instance [overlappable] (Transformable l l', Transformable r r') => 
           Transformable (Either l r) (Either l' r') 
     -- Defined at Handler/GLEnterReceiptSheet/ReceiptRow.hs:154:31 
     instance [overlap ok] Transformable a a 
     -- Defined at Handler/GLEnterReceiptSheet/ReceiptRow.hs:151:27 

私はOVERLAPSOVERLAPPINGOVERLAPPABLEの異なる組み合わせを試してみましたが、何も働きません。これをどうすれば解決できますか?

答えて

7

あなたは、インスタンス定義の1つ変更する必要があります:

class Transformable a b where 
    transform :: a -> b 

-- this one 
instance {-# OVERLAPS #-} (a ~ b) => Transformable a b where 
    transform x = x 

instance (Transformable l l', Transformable r r') 
     => Transformable (Either l r) (Either l' r') where 
    transform = either (Left . transform) (Right . transform) 

test0 :: (Transformable a a', Transformable b b') => Either a b -> Either a' b' 
test0 = transform 

を、コードに関係なく、あなたが他のインスタンスで使用重なるの動作します。 2番目のインスタンスにプラグマは実際には必要ありません。

元のコードの問題は、インスタンスが実際にちょうど重なった支離滅裂、ではないので、{-# OVERLAPS/OVERLAPPING/OVERLAPPABLE #-}のない組み合わせがあなたを救うないだろうということです - あなたは望ましくない{-# INHCOHERENT #-}を使用する必要があるだろうと私はお勧めしません。 GHCはエラーメッセージでは、この矛盾をご紹介します:

>:t transform :: (Transformable a a', Transformable b b') => Either a b -> Either a' b' 

<interactive>:1:1: Warning: 
    Overlapping instances for Transformable 
           (Either a1 b1) (Either a'1 b'1) 
     arising from a use of `transform' 
    Matching instances: 
     instance [overlappable] (Transformable l l', Transformable r r') => 
           Transformable (Either l r) (Either l' r') 
     -- Defined at test6.hs:9:31 
     instance [overlap ok] Transformable a a -- Defined at test6.hs:6:27 
    (The choice depends on the instantiation of `a1, b1, a'1, b'1' 
    To pick the first instance above, use IncoherentInstances 
    when compiling the other instance declarations) 
    In the expression: 
     transform :: 
      (Transformable a a', Transformable b b') => 
      Either a b -> Either a' b' 

基本的には、オーバーラップインスタンスから選択するためには、1つのインスタンスはあなたが一致しようとしているタイプ(S)のための「最も具体的」でなければなりません。これの詳細は、user guideに記載されています。

+2

私はユーザーガイドを読もうとしましたが、何も分かりません。 「変形可能なa a」と「a〜b =>変形可能なa b」との違いを説明してください。彼らは私にとっても同じように見えます。 – mb14

+0

@ mb14の場合、「OverlappingInstances」のドキュメントの複雑さは、それが悪い考えであることを私に納得させるものの1つです。それ以来、私はそれが「侵入的」であるという証拠の良いビットを見て、あらゆる種類の良い直感を破った。私は本当にファンではありません。 – dfeuer

+0

@dfeur私は同意するが、その場合、私は本当に選択肢がない。最も厄介なことは、重複しているインスタンスが実際に実装されていることです。したがって、実際にはオーバーラップはありません。また、どちらかのインスタンスに不等理制約を追加できれば、この問題は発生しません。 – mb14

関連する問題