How to resolve overlapping instance

只谈情不闲聊 提交于 2021-02-06 20:45:02

问题


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 ?


回答1:


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.



来源:https://stackoverflow.com/questions/36913922/how-to-resolve-overlapping-instance

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!