Haskell 使用Numeric Prelude中的加法类会导致实例重叠

Haskell 使用Numeric Prelude中的加法类会导致实例重叠,haskell,overlapping-instances,Haskell,Overlapping Instances,在尝试使用数字前奏定义一些数学对象时,我遇到了一个问题。加法类型类定义了一个实例 instance Additive.C v => Additive.C [v] 我读到“如果v是加法,[v]太多”(显然我错了)。它的实现类似于 (+) x y = map (\(a,b) -> a + b) $ zip x y 所以[1,2,3]+[4,5,6]=[5,7,9]对于我想做的事情来说是无用的。我想我不会有问题,因为我的v型不是加法。不幸的是,我仍然得到了一个重叠的实例错误,我发现非常

在尝试使用数字前奏定义一些数学对象时,我遇到了一个问题。加法类型类定义了一个实例

instance Additive.C v => Additive.C [v]
我读到“如果v是加法,[v]太多”(显然我错了)。它的实现类似于

(+) x y = map (\(a,b) -> a + b) $ zip x y
所以[1,2,3]+[4,5,6]=[5,7,9]对于我想做的事情来说是无用的。我想我不会有问题,因为我的v型不是加法。不幸的是,我仍然得到了一个重叠的实例错误,我发现非常混乱。我做了一些阅读,现在我明白了,出于某种原因,Haskell忽略了“=>”位之前的所有内容,因此我应该将默认实例解读为“任何列表在默认实例的意义上都可能是可添加的”。尽管这个扩展有“危险”的名声,我还是尝试过使用重叠实例,但即使这样似乎也没有帮助

这是我的测试用例

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses,FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-} --This doesn't seem to help
import NumericPrelude

import qualified Algebra.Additive    as Additive

data Test = Red | Green | Blue deriving Show

instance Additive.C [Test] where
   zero = undefined
   (+) =  undefined
   negate = undefined

test = [Red] + [Green] + [Blue]
产生错误(更新:这似乎只发生在GHC的旧版本中。版本7.2.2似乎接受此错误):


这是否意味着我不能使用列表,因为我不想使用addition的默认实例?我真正想做的是告诉ghc忘记那个默认实例,有可能吗?如果没有,除了删除列表,我不确定从这里走到哪里。

编辑:正如@kosmikus提到的,您的示例对我也很有用。我正在使用ghc 7.4.1

不能让编译器忘记实例,因为一旦导入模块,实例就在中定义。请注意,
OverlappingInstances
不会告诉编译器忘记一个实例,而是使用可用的最详细的实例

为了防止实例重叠,可以使用类型包装器来区分任意列表和正在使用的列表。例如,您可以定义

data TestList = TestList [Test]
然后,您可以为
TestList
定义类型类的自定义实例。在大多数情况下,人们使用记录语法为列表定义访问器,因为您必须包装和展开列表

data TestList = TestList { list :: [Test] }
为了降低额外构造函数的成本,您可以使用
newtype
而不是
data

newtype TestList = TestList { list :: [Test] }

newtype
可能只有一个参数,编译器基本上会将其当作不存在的参数来处理,但会使用构造函数提供的类型信息,在选择正确的实例时将列表与任意列表区分开来。

编辑:正如@kosmikus提到的,您的示例对我来说很好,也我正在使用ghc 7.4.1

不能让编译器忘记实例,因为一旦导入模块,实例就在中定义。请注意,
OverlappingInstances
不会告诉编译器忘记一个实例,而是使用可用的最详细的实例

为了防止实例重叠,可以使用类型包装器来区分任意列表和正在使用的列表。例如,您可以定义

data TestList = TestList [Test]
然后,您可以为
TestList
定义类型类的自定义实例。在大多数情况下,人们使用记录语法为列表定义访问器,因为您必须包装和展开列表

data TestList = TestList { list :: [Test] }
为了降低额外构造函数的成本,您可以使用
newtype
而不是
data

newtype TestList = TestList { list :: [Test] }

newtype
可能只有一个参数,编译器基本上会将其当作不存在的参数来处理,但在选择正确的实例时,会使用构造函数提供的类型信息来区分列表和任意列表。

您希望从
list1+list2
中获得什么行为?(另外,就风格而言,
zipWith(+)xy
是编写
map(\(a,b)->a+b)$zip xy
)的一种更好的方式,如果我尝试用GHC 7.4.2加载您的测试用例,我不会出错。您希望从
list1+list2
中获得什么行为?(同样,就风格而言,
zipWith(+)xy
是编写
地图(\(a,b)->a+b)$zip xy
的更好方法如果我尝试用GHC 7.4.2加载您的测试用例,我不会出错。好的,谢谢。我会使用解决方案,因为我对Haskell还是很陌生,我不想开始启用被认为是危险的扩展。好的,谢谢。我会使用解决方案,因为我对Haskell还是很陌生,我不想开始启用被认为是危险的扩展我们。