0

在尝试使用 Numeric prelude 定义一些数学对象时,我遇到了一个问题。Additive 类型类定义了一个实例

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 类型不是 Additive。不幸的是,我仍然遇到了一个重叠的实例错误,我发现这非常令人困惑。我做了一些阅读,现在我明白了,出于某种原因,Haskell 忽略了“=>”位之前的所有内容,所以我应该将默认实例阅读为“任何列表在默认实例的意义上都可能是附加的”。尽管这个扩展有“危险”的名声,但我尝试过使用 OverlappingInstances,但即使这样似乎也无济于事。

这是我的测试用例。

{-# 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 似乎接受它):

Overlapping instances for Additive.C [Test]
  arising from a use of `+'
Matching instances:
  instance Additive.C v => Additive.C [v]
    -- Defined in Algebra.Additive
  instance [overlap ok] Additive.C [Test]
    -- Defined at Testcase.hs:10:10-26
In the first argument of `(+)', namely `[Red] + [Green]'
In the expression: [Red] + [Green] + [Blue]
In an equation for `test': test = [Red] + [Green] + [Blue]

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

4

1 回答 1

5

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

您不能让编译器忘记该实例,因为它是在您导入模块后立即导入的,该实例是在其中定义的。请注意,OverlappingInstances这并不告诉编译器忘记一个实例,而是采用最指定的可用实例。

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

data TestList = TestList [Test]

然后,您可以为TestList. 在大多数情况下,人们使用记录语法来定义列表的访问器,因为您必须包装和打开列表。

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

为了减少额外构造函数的成本,您可以使用 anewtype而不是 a data

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

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

于 2012-08-26T17:57:05.353 回答