假设我们有以下内容:
{-# LANGUAGE FlexibleInstances #-}
module Sample where
newtype A a =
A a
deriving (Show)
newtype L a =
L [a]
class ListContainer l where
getList :: l a -> [a]
instance ListContainer L where
getList (L l) = l
instance (Show a, ListContainer l) => Show (l a) where
show = const "example"使用此代码,ghc抱怨:
warning: [-Wdeferred-type-errors]
• Overlapping instances for Show (A a)
arising from a use of ‘GHC.Show.$dmshowList’
Matching instances:
instance (Show a, ListContainer l) => Show (l a)
-- Defined at /.../src/Sample.hs:18:10
instance Show a => Show (A a)
-- Defined at /.../src/Sample.hs:7:13
• In the expression: GHC.Show.$dmshowList @(A a)
In an equation for ‘showList’:
showList = GHC.Show.$dmshowList @(A a)
When typechecking the code for ‘showList’
in a derived instance for ‘Show (A a)’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Show (A a)’
warning: [-Wdeferred-type-errors]
• Overlapping instances for Show (A a)
arising from a use of ‘GHC.Show.$dmshow’
Matching instances:
instance (Show a, ListContainer l) => Show (l a)
-- Defined at /.../src/Sample.hs:18:10
instance Show a => Show (A a)
-- Defined at /.../src/Sample.hs:7:13
• In the expression: GHC.Show.$dmshow @(A a)
In an equation for ‘show’: show = GHC.Show.$dmshow @(A a)
When typechecking the code for ‘show’
in a derived instance for ‘Show (A a)’:
To see the code I am typechecking, use -ddump-deriv
In the instance declaration for ‘Show (A a)’我可以理解,它认为a类型可以派生Show,也可以派生ListContainer,这可能导致Show。
我们怎么才能避免呢?
我知道有一个函数showList,但是它的签名有点陌生。我已经有了一个函数,用于显示某些列表,它直接返回String。
发布于 2019-05-02 12:16:44
我能理解的是,它认为
a类型可以是派生Show,也可以是派生ListContainer,这可能会导致Show。
这不是它所想的。
当Haskell选择类实例时,它根本不考虑实例约束。在选择实例时,它只考虑实例头(类名后面的内容)。
在您的Show实例中,实例头是l a。此实例头与A a匹配(假设为l = A)。顺便说一句,它还匹配了许多其他东西--例如,它匹配Maybe a (其中l = Maybe)、Either b a (与l = Either b)、Identity a和IO a --想想看,几乎每种类型都有一个类型参数。A、Maybe和IO都没有ListContainer的实例,这并不重要,因为正如我前面所说的,Haskell在选择实例时不考虑约束,只是在实例头上。
只有在找到匹配实例(通过头上的匹配)之后,Haskell才会检查该实例的约束实际上是否得到满足。如果他们不这样做的话,他们会抱怨,但它永远不会回去,转而选择另一个例子。
所以回到您的示例:因为A现在有两个匹配的Show实例--它自己的派生实例和您编写的Show (l a)实例,编译器抱怨它们是重叠的。
发布于 2019-05-02 08:18:32
在您的示例中,只需删除instance (Show a, ListContainer l) => Show (l a)并将deriving (Show)添加到L定义中即可。
或者,您可以从deriving (Show)定义中删除A。
如果您希望代码按照现在的样子运行,请删除deriving (Show)并显式地实现它。
instance {-# OVERLAPPING #-} Show a => Show (A a)
where
show (A a) = "A " ++ show ahttps://stackoverflow.com/questions/55947743
复制相似问题