概括加法时的GHC重叠实例

时间:2016-08-29 20:58:58

标签: haskell typeclass overlapping-instances

尝试将(+)推广到Num以上,我写了一个Addable类:

{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}

class Addable a where
  (+) :: Addable a => a -> a -> a

instance Addable [a] where
  (+) = (++)

instance Num a => Addable a where
  (+) = (Prelude.+)

当尝试添加(连接)列表时,GHC抱怨重叠实例:

*Test> "abc" + "defghi"

<interactive>:84:7:
    Overlapping instances for Addable [Char] arising from a use of `+'
    Matching instances:
      instance Num a => Addable a -- Defined at Utils.hs:23:10
      instance Addable [a] -- Defined at Utils.hs:20:10
    In the expression: "abc" + "defghi"
    In an equation for `it': it = "abc" + "defghi"

我知道GHC在选择类型类的实例时会忽略上下文,因此尝试在Addable [a]Addable a之间进行选择确实是个问题。但是,我希望GHC选择第一个定义,因为它更具体。 为什么不发生这种情况?

此外,这个问题有一个优雅的解决方法吗?或者我是从错误的角度去做这个?

1 个答案:

答案 0 :(得分:4)

您需要启用重叠实例才能实际使用它们。在旧版本的编译器中,您可以使用OverlappingInstances扩展名为每个模块执行此操作:

{-# LANGUAGE OverlappingInstances #-}

这适用于此代码:

λ> :set -XOverlappingInstances
λ> "abc" + "def"
"abcdef"

但是,这种方法在较新版本的GHC中被弃用(至少在8.0中):

Misc.hs:1:73-92: warning: …
    -XOverlappingInstances is deprecated: 
      instead use per-instance pragmas OVERLAPPING/OVERLAPPABLE/OVERLAPS

因此,更现代的方法是在每个实例的基础上指定它:

instance {-# OVERLAPPABLE #-} Num a => Addable a where
  (+) = (Prelude.+)

OVERLAPPINGOVERLAPSINCOHERENT也存在此样式的pragma,允许您使用这些属性注释特定实例。