2016-04-28 6 views
6

Ho il seguente codice (trasformare è simile per convertire)Come risolvere la sovrapposizione esempio

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 

Naturalmente, quei casi si sovrappongono nel caso in cui sto cercando di trasformare Either a b-Either a b e ottenere il seguente messaggio di errore (ParsingError è un tipo alias per 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 

ho provato diverse combinazioni di OVERLAPS, OVERLAPPING e OVERLAPPABLE ma non funziona niente. Come posso risolvere questo ?

risposta

7

Si dovrà cambiare una delle definizioni istanza:

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 

E il codice funzionerà a prescindere che si sovrappongono si utilizza sul l'altra istanza. In realtà non hai bisogno di alcun pragma sulla seconda istanza.

Il problema con il codice originale è che i casi sono in realtà incoerenti, non solo si sovrappongono, in modo da nessuna combinazione di {-# OVERLAPS/OVERLAPPING/OVERLAPPABLE #-} si risparmierebbero - si avrebbe bisogno di utilizzare {-# INHCOHERENT #-}, che non è auspicabile e io non lo consiglio . GHC vi dirà su questo incoerenze nel messaggio di errore:

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

In sostanza, al fine di raccogliere dalle istanze sovrapposte, un'istanza deve essere "più specifico" per il tipo di (s) che si sta cercando di abbinare. I dettagli di questo sono indicati nello user guide.

+2

Ho provato a leggere la guida dell'utente ma non capisco nulla. Potresti spiegare la differenza tra 'Trasformabile a a' e' a ~ b => Trasformabile a b' e perché uno è incorporo mentre l'altro è ok. Hanno lo stesso aspetto per me. – mb14

+0

@ mb14, la complessità della documentazione di 'OverlappingInstances' è una delle cose che mi ha convinto che è una cattiva idea. Da allora ho visto una buona prova che è "invadente", rompendo ogni sorta di intuizione altrimenti buona. Non sono davvero un fan. – dfeuer

+0

@dfeur Sono d'accordo, tuttavia in quel caso non ho davvero la scelta. Il più fastidioso è che quelle istanze sovrapposte hanno in effetti l'implementazione, quindi in pratica non c'è sovrapposizione. Inoltre, non avrei questo problema se potessi aggiungere un vincolo di disuguaglianza nell'istanza Either. – mb14