您必须更改实例定义之一:
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 #-}
会拯救你 - 你需要使用{-# INCOHERENT #-}
,这是不可取的,我不会推荐它。 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'
本质上,为了从重叠的实例中进行选择,一个实例对于您尝试匹配的类型必须是“最具体的”。详细信息在用户指南 https://downloads.haskell.org/%7Eghc/latest/docs/html/users_guide/glasgow_exts.html#overlapping-instances.