2016-04-28 10 views
6

Ich habe den folgenden Code (Transform ähnelt konvertieren)Wie Instanz überlappend lösen

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 

Natürlich diese Instanzen im Fall überlappen, wo ich versuche Either a b-Either a b zu transformieren und die folgende erhalten Fehlermeldung (ParsingError ist eine Art Alias ​​für Either 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 

ich andere Kombination von OVERLAPS, OVERLAPPING und OVERLAPPABLE aber nichts funktioniert versucht. Wie kann ich das lösen?

Antwort

7

Sie haben eine der Instanzdefinitionen ändern:

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 

Und der Code funktioniert unabhängig davon, welche überlappen Sie auf der anderen Instanz. Sie brauchen eigentlich kein Pragma bei der zweiten Instanz.

Das Problem mit dem Original-Code ist, dass die Fälle sind tatsächlich inkohärent, nicht nur überlappend, so dass keine Kombination von {-# OVERLAPS/OVERLAPPING/OVERLAPPABLE #-} würden Sie sparen - Sie müssten {-# INHCOHERENT #-} verwenden, was nicht erwünscht ist, und ich würde nicht empfehlen, . GHC werden Sie diesen Inkohärenz in der Fehlermeldung sagen:

>: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' 

Wesentlichen um aus überlappenden Instanzen zu holen, muss eine Instanz sein „spezifischste“ für die Art (en) Sie zu entsprechen versuchen. Die Details dazu sind in der user guide angegeben.

+2

Ich habe versucht, das Benutzerhandbuch zu lesen, aber ich verstehe nichts. Könntest du den Unterschied erklären zwischen "Transformable a a" und "a ~ b => Transformable a b" und warum man inkorrekt ist, während das andere in Ordnung ist. Sie sehen für mich gleich aus. – mb14

+0

@ mb14, ist die Komplexität der Dokumentation für "OverlappingInstances" eines der Dinge, die mich davon überzeugt haben, dass es eine schlechte Idee ist. Seitdem habe ich eine Menge Beweise dafür gesehen, dass es "aufdringlich" ist und alle möglichen guten Intuitionen bricht. Ich bin wirklich kein Fan. – dfeuer

+0

@dfeur Ich stimme zu, aber in diesem Fall habe ich nicht wirklich die Wahl. Am ärgerlichsten ist, dass diese überlappenden Instanzen tatsächlich die Implementierung haben, so dass es in der Praxis keine Überlappung gibt. Außerdem hätte ich dieses Problem nicht, wenn ich eine Ungleichheitsbedingung für die EASY-Instanz hinzufügen könnte. – mb14

Verwandte Themen