4

我有一些这样的代码:

{-# 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,因为这无关紧要。)

4

1 回答 1

2

这并不是您问题的真正答案,更像是一个扩展评论,建议如何解决问题的另一条路线。

在 Haskell 中,规范的解决方案是为您的每个实例创建一个newtype,这可能不是您想要的。但是,我想建议您另一种方法。

在 Haskell 中,我们基本上有 3 种可能性来构造数据类型:

  1. 使用积和联积(不相交联合)的代数数据类型。
  2. 函数类型。
  3. 原始类型。

对于第一部分,我们可以使用SYBGHC Generics。如果一个产品是空的,或者有一个空因子,它会映射到a -> Void。并且一个联积映射到a -> Void当且仅当它的所有加法。

如果两者和都是,则函数类型a -> b是建设性的:ab

instance (Constructive a, Constructive b) => Constructive (a -> b) where
  ...

若非x :: b空,a -> b则有const x。如果a是空a -> b的则由 居住absurd。如果a非空且b为空,则a -> b映射到Void.

所有 Haskell 原始类型都是非空的,所以它们是微不足道的建设性的。

不幸的是,似乎没有办法告诉 GHC 所有数据类型都是这三种中的一种。我的建议是实现实例->,然后要么

  • 尝试使用 SYB 为所有实现Data. 仍然存在如何处理重叠实例的问题。或者:
  • 尝试使用 GHC 泛型为 ADT 提供默认实例,并为原始类型手动实现实例。这意味着对于每种数据类型,您仍然必须提供一个空instance实现,默认值由泛型提供。

写完之后,我发现了AdvancedOverlap。也许将它与以前的方法之一结合起来可能会产生一个很好的解决方案。

于 2016-01-03T09:49:56.450 回答