私は現在、クラスのいくつかのインスタンスを派生させるプロジェクトで作業しています。クラスにはいくつかのケースで同じ定義を保存するメソッドが1つしかないので、オーバーラップ可能な一般的なインスタンスを定義し、重複する必要があるものを定義してみました。重複するインスタンスの問題
重複するインスタンスエラーが発生するため、これは機能しません。いくつかのテストをして、私たちは、私の元の問題にかなり多くの同等です。この減少した例accrossに来た:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, MultiParamTypeClasses #-}
module Instance where
data Id a = Id a String
data C a = C a
class Bad a b where
bad :: a -> String
instance {-# OVERLAPPABLE #-} Bad a b where
bad = \_ -> "Default case"
instance {-# OVERLAPPING #-} Bad (Id a) (C a) where
bad = \_ -> "Id"
class Good a b where
good :: a -> String
instance {-# OVERLAPPABLE #-} Good a b where
good = \_ -> "Default case"
instance {-# OVERLAPPING #-} Good (Id a) b where
good = \_ -> "Id"
test = let a = Id() "a"
in putStrLn (good a) >> putStrLn (bad a)
(あなたが二悪いのインスタンスをコメントしていない限り、これはコンパイルされませんので注意してください。)
クラス良い作品(テスト出力「Id」)。私が悪いため2番目のインスタンスを削除しない場合は、私が手:
Overlapping instances for Bad (Id()) b0
arising from a use of ‘bad’
Matching instances:
instance [overlappable] Bad a b -- Defined at Instance.hs:12:31
instance [overlapping] Bad (Id a) (C a)
-- Defined at Instance.hs:15:30
(The choice depends on the instantiation of ‘b0’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
In the first argument of ‘putStrLn’, namely ‘(bad a)’
In the second argument of ‘(>>)’, namely ‘putStrLn (bad a)’
In the expression: putStrLn (good a) >> putStrLn (bad a)
私は理解していないことは、それらの間の唯一の違いは、2番目のクラスのパラメータでaditional制限されたときに、なぜこれが起こるんです。
重複エラーを避けるために、重ねて表示できるインスタンスのポイントではありませんか?
よろしく
これらのクラスは実際には機能しません。クラス内の関数は変数 'b'に言及せず、' a'から 'b'を決定するためのfundepなどはありません。 「良い」は顕著な偶然のためにのみ作用します.-両方とも「良い」の場合と、2番目のタイプが完全に制限のないタイプの変数の場合です。これは、クラスに型変数がまったくない場合と本質的に同じです。 'b'は後で' C a'にインスタンス化され、どのインスタンスが選択されているかを変更する( "選択はインスタンス化に依存する")完全に自由な型の変数であるため、 '悪い 'は機能しません。 – user2407038
あなたのプラグマは 'UndecidableInstances'の代わりに' AllowAmbiguousTypes'を持つべきだと思います。そうでなければ、 'bad :: Bad ab => a - > String'の' b'にあいまいなエラーを返します。 – Alec
@ user2407038はい、私はそれを見ることができますが、関数にbを追加するとエラーは残っています。もう少しテストすると、基本的に関数を使用しなければならないことがわかりましたが、明示的にbが何であるかをghcはどのインスタンスを使用するのか知っています。私はこの小さな例をうまく利用することができましたが、これは大きなプロジェクトでは実行可能ではないと私は考えています。ありがとう! –