我得到了错误:
Duplicate instance declarations:
instance [overlap ok] EnumTag a => Read a
-- Defined at /XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/intero/intero2932Xpa-TEMP.hs:110:27
instance [overlap ok] StrTag a => Read a
-- Defined at /XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/intero/intero2932Xpa-TEMP.hs:121:27 (intero)对于此代码:
class (Show a, Enum a) => EnumTag a where
anyEnum :: a
instance {-# OVERLAPS #-} EnumTag a => Read a where
readPrec = RP.lift P.skipSpaces >> expectEnum
instance {-# OVERLAPS #-} EnumTag a => Eq a where
a == b | a == anyEnum || b == anyEnum = True
| otherwise = fromEnum a == fromEnum b
class StrTag a where
anyStr :: a
tagPrefix :: a -> String -- ^ should be constant
toStr :: String -> a
instance {-# OVERLAPS #-} StrTag a => Read a where
readPrec = parens $ do
RP.lift P.skipSpaces
(RP.lift $ expectShown anyStr) <++ RP.lift g
where g = do
Just s@(_:_) <- L.stripPrefix tagPrefix <$> expectTag
return $ toStr s为什么会这样?第一个实例中的Read a只有当a为EnumTag时才有效,第二个实例中-只有当a为StrTag时才有效。
如何修复此错误并为EnumTag和StrTag创建“默认”实例,以便客户端代码将简单地“继承”这些功能(读取),只需实例化EnumTag或StrTag?
发布于 2017-12-01 20:31:54
重叠的实例非常脆弱。可以说,它们永远不应该被使用。
无论如何,重叠的实例会导致GHC避免过早提交实例。例如。
-- overlapping
instance ... => Read [Int] -- 1
instance ... => Read [a] -- 2当GHC必须解决诸如Read [b]之类的约束时,它不会提交到实例2,因为它不能排除更具体的实例1:毕竟,类型变量b稍后可能会被发现为Int。
如果稍后发现b为Int,则将选择实例1。如果发现b为String,则GHC将选择instance 2。
然而,这要求在每种情况下都有一个“最佳选择”。也就是说,当b = Int时,两个实例都可以使用,但1更具体,因此它是“最好的”,而GHC选择它。
instance ... => Read [a] -- 3
instance ... => Read [a] -- 4那么就不存在最好的实例,因为它们使用相同的头Read [a],这使得选择本质上是模棱两可的,而GHC拒绝了这一点。
可能让你感到困惑的是,GHC永远不会考虑=> (“上下文”)左边的内容来选择一个实例。一旦考虑到实例的上下文,实例是否会重叠并不重要,因为没有任何类型可以同时满足3和4的上下文。一般来说,检测上下文互斥是非常困难的,GHC甚至不会尝试这样做。仅考虑实例头部(在=>的右侧)。
除非客户端定义了一个更具体的实例,否则无法创建这两个自动打开的默认实例。
我更喜欢避免实例中的重叠,并在实例之外提供默认实现。例如。
-- library
readPrec_fromStrTag :: StrTag a => Int -> ReadS a
readPrec_fromStrTag = parens $ do
RP.lift P.skipSpaces
(RP.lift $ expectShown anyStr) <++ RP.lift g
where g = do
Just s@(_:_) <- L.stripPrefix tagPrefix <$> expectTag
return $ toStr s如果客户端想要使用它,他们可以使用以下命令启用默认实现
instance StrTag T where
...
instance Read T where
readPrec = readPrec_fromStrTag -- use default from the library如果这个模板和其他模板变得太麻烦,模板Haskell可能会帮助用户编写它。
https://stackoverflow.com/questions/47592742
复制相似问题