GHC 概括加法时的重叠实例
GHC Overlapping instances when generalising addition
试图将 (+)
推广到不仅仅是 Num
s,我写了一个 Addable
class:
{-# 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 在选择类型 classes 的实例时会忽略上下文,因此尝试在 Addable [a]
和 Addable a
之间进行选择确实是一个问题。但是,我希望 GHC 选择第一个定义,因为它更具体。 为什么没有发生这种情况?
此外,是否有解决此问题的优雅解决方法?还是我从错误的角度出发?
您需要启用重叠实例才能真正使用它们。在旧版本的编译器中,您可以使用 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.+)
OVERLAPPING
、OVERLAPS
和 INCOHERENT
也存在这种样式的 pragma,让您可以使用这些属性注释特定实例。
试图将 (+)
推广到不仅仅是 Num
s,我写了一个 Addable
class:
{-# 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 在选择类型 classes 的实例时会忽略上下文,因此尝试在 Addable [a]
和 Addable a
之间进行选择确实是一个问题。但是,我希望 GHC 选择第一个定义,因为它更具体。 为什么没有发生这种情况?
此外,是否有解决此问题的优雅解决方法?还是我从错误的角度出发?
您需要启用重叠实例才能真正使用它们。在旧版本的编译器中,您可以使用 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.+)
OVERLAPPING
、OVERLAPS
和 INCOHERENT
也存在这种样式的 pragma,让您可以使用这些属性注释特定实例。