Как разрешить перекрывающийся экземпляр
у меня есть следующий код (преобразование, аналогичное преобразование)
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
to 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
но ничего не работает. Как я могу это решить ?
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
и код будет работать независимо от того, какое перекрытие вы используете в другом экземпляре. На самом деле вам не нужна никакая ПРАГМА во втором экземпляре.
проблема с исходным кодом заключается в том, что таких случаев на самом деле некогерентного, не просто перекрывается, поэтому нет комбинации {-# 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'
по существу, чтобы выбрать из перекрывающихся экземпляров, один экземпляр должен быть "наиболее конкретным" для типа(ов), который вы пытаетесь сопоставить. Подробности этого приведены в руководство пользователя.