I have the following code (transform is similar to convert)
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
Of course, those instances overlap in the case where I'm trying to transform Either a b
to Either a b
and get the following error message (ParsingError
is a type alias for 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
I tried different combination of OVERLAPS
, OVERLAPPING
and OVERLAPPABLE
but nothing works. How can I solve this ?
You will have to change one of the instance definitions:
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
And the code will work regardless of which overlap you use on the other instance. You don't actually need any pragma on the second instance.
The problem with the original code is that the instances are actually incoherent, not just overlapping, so no combination of {-# OVERLAPS / OVERLAPPING / OVERLAPPABLE #-}
would save you - you would need to use {-# INCOHERENT #-}
, which is not desirable and I wouldn't recommend it. GHC will tell you about this incoherence with the error message:
>: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'
Essentially, in order to pick from overlapping instances, one instance must be "most specific" for the type(s) you are trying to match. The details of this are given in the user guide.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With