2016-04-28 18 views
6

Mam następujący kod (przekształcać jest podobna do konwersji)Jak rozwiązać nakładających instancja

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 

Oczywiście, te przypadki zachodzą w przypadku, gdy próbuję przekształcić Either a b do Either a b i uzyskać następujące komunikat o błędzie (ParsingError jest alias typ dla 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 

próbowałem różnych kombinacji OVERLAPS, OVERLAPPING i OVERLAPPABLE ale nic nie działa. Jak mogę to rozwiązać?

Odpowiedz

7

Trzeba będzie zmienić jeden z definicjami przykład:

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 

I kod będzie działać niezależnie od tego, które pokrywają się użyć drugiej instancji. Właściwie nie potrzebujesz żadnej pragmy w drugiej instancji.

Problem z oryginalnego kodu jest to, że przypadki są rzeczywiście niespójne, nie tylko pokrywają się, więc żadna kombinacja {-# OVERLAPS/OVERLAPPING/OVERLAPPABLE #-} by cię uratować - trzeba by użyć {-# INHCOHERENT #-}, co nie jest pożądane, a ja nie polecam . GHC powie Ci o tym niespójności w komunikacie o błędzie:

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

Zasadniczo, aby wybrać z nakładających przypadkach jedna instancja musi być „najbardziej specyficzne” dla typu (-ów), który próbujesz dopasować. Szczegóły tego są podane w user guide.

+2

Próbowałem przeczytać instrukcję obsługi, ale nic nie rozumiem. Czy mógłbyś wyjaśnić różnicę między 'Transformable a a' a ~ b => Transformable a b' i dlaczego jeden jest niepoprawny, podczas gdy drugi jest w porządku. Wyglądają tak samo dla mnie. – mb14

+0

@ mb14, złożoność dokumentacji "OverlappingInstances" jest jedną z rzeczy, które przekonały mnie, że to zły pomysł. Od tego czasu widziałem sporo dowodów na to, że jest "inwazyjny", łamiąc wszelkiego rodzaju dobrą intuicję. Naprawdę nie jestem fanem. – dfeuer

+0

@ .Feur Zgadzam się, jednak w tym przypadku tak naprawdę nie mam wyboru. Najbardziej denerwujące jest to, że nakładające się instancje mają faktycznie zastosowanie, więc w praktyce nie ma nakładania się. Ponadto, nie miałbym tego problemu, gdybym mógł dodać ograniczenie nierówności w każdej instancji. – mb14