我有一些像这样的代码:
{-# OPTIONS_GHC -Wall #-}
{-# LANUAGE VariousLanguageExtensionsNoneOfWhichWorked #-}
import Control.Applicative
import Data.Either
import Data.Void
class Constructive a where
lem :: Either (a -> Void) a
instance Constructive Void where
lem = Left id
instance Num a => Constructive a where
lem = Right 0
instance Enum a => Constructive a where
lem = Right $toEnum 0
instance Bounded a => Constructive a where
lem = Right minBound
instance Monoid a => Constructive a where
lem = Right mempty
instance Alternative f => Constructive (f a) where
lem = Right empty
问题是,GHC抱怨
pad.hs:49:10:
Duplicate instance declarations:
instance [overlap ok] Bounded a => Constructive a
-- Defined at pad.hs:49:10
instance [overlap ok] Monoid a => Constructive a
-- Defined at pad.hs:52:10
伴随着一堆类似的错误.
有没有办法告诉GHC随机选择一个,因为我不关心它使用的是什么? (我甚至不在乎每次使用lem时它是否选择不同的,因为它没关系.)
最佳答案 这不是你问题的真正答案,更像是一个扩展的评论,暗示了如何解决问题的另一条路线.
在Haskell中,规范的解决方案是为每个实例创建一个newtype,这可能不是你想要的.但是,我想建议你另一种方法.
在Haskell中,我们基本上有3种可能性来构建数据类型:
>使用产品和coproducts(不相交的联合)的代数数据类型.
>功能类型.
>原始类型.
对于第一部分,我们可以使用SYB或GHC Generics.如果产品为空,或者具有空因子,则映射到 – >虚空.并且副产品映射到 – >如果它的所有加数都没有效果.
函数类型a – >如果a和b都是:b则是建设性的:
instance (Constructive a, Constructive b) => Constructive (a -> b) where
...
如果x :: b是非空的,则a – > b由const x居住.如果a为空,那么a – > b荒谬居住.如果a非空并且b为空,则a – > b映射到Void.
所有Haskell原始类型都是非空的,因此它们非常具有建设性.
不幸的是,似乎没有办法告诉GHC所有数据类型都是这三种中的一种.我的建议是实现 – >的实例.然后要么
>尝试使用SYB为实现Data
的所有内容实现实例.如何处理重叠实例仍然存在问题.要么:
>尝试使用GHC Generics为ADT提供默认实例,并为原始类型手动实现实例.这意味着对于每种数据类型,您仍然必须提供空实例实现,默认情况下由Generics提供.
写完这篇文章之后,我发现了AdvancedOverlap.也许将它与之前的方法结合起来可以找到一个很好的解决方案.