2016-04-28 3 views
6

У меня есть следующий код (преобразование аналогичен преобразование)Как разрешить перекрывающийся экземпляр

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 b в Either a b и получить следующий сообщение об ошибке (ParsingError типа псевдоним 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 

Я пробовал различные комбинации из OVERLAPS, OVERLAPPING и OVERLAPPABLE, но ничего не работает. Как я могу это решить?

ответ

7

Вы должны изменить одно из определений, например:

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 

И код будет работать независимо от того, который вы используете перекрываться на другом экземпляре. Фактически вам не нужна прагма для второго экземпляра.

Проблема с исходным кодом является то, что экземпляры фактически некогерентного, а не просто перекрываются, так что ни комбинация {-# 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' 

По сути, для того, чтобы выбрать из перекрывающихся экземпляров, один экземпляр должен быть «наиболее специфичным» для типа (ов), вы пытаетесь соответствовать. Детали этого приведены в user guide.

+2

Я попытался прочитать руководство пользователя, но я ничего не понимаю. Не могли бы вы объяснить разницу между 'Transformable a a' и' a ~ b => Transformable a b' и почему один является инкорпорированным, тогда как другой - в порядке. Они выглядят одинаково для меня. – mb14

+0

@ mb14, сложность документации для 'OverlappingInstances' является одной из вещей, которые убедили меня, что это плохая идея. С тех пор я видел немало доказательств того, что это «навязчивый», ломающий всевозможную доброжелательную интуицию. Я действительно не поклонник. – dfeuer

+0

@dfeur Согласен, однако в этом случае у меня действительно нет выбора. Наиболее раздражает то, что эти перекрывающиеся экземпляры на самом деле являются реализацией, поэтому на практике нет перекрытия. Кроме того, у меня не было бы этой проблемы, если бы я мог добавить ограничение неравенства в любом экземпляре. – mb14

Смежные вопросы