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] }

追加のコンストラクターのコストを削減するために、 のnewtype代わりに を使用できますdata

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

Anewtypeは単一の引数しか持たない場合があり、コンパイラは基本的にそれが存在しないかのように処理しますが、コンストラクターが提供する型情報を使用して、正しいインスタンスを選択するときにリストを任意のリストと区別します。

于 2012-08-26T17:57:05.353 に答える