4

この重複するインスタンスのエラー メッセージに困惑しています。申し訳ありませんが、これは重要なプロジェクトですが、エラーは型シグネチャに対してローカルである必要があります。

まず、 fが特定の型であることを宣言します。

let f = undefined :: (CompNode Int)

次に、関数を呼び出そうとしますpshow :: PrettyShow a => a -> String。このエラー メッセージが表示されます。

> pshow f

<interactive>:1:1:
    Overlapping instances for PrettyShow (CompNode Int)
      arising from a use of `pshow'
    Matching instances:
      instance (G.Graph g, PrettyShow (G.Vertex g)) => PrettyShow g
        -- Defined at Graph.hs:61:10-57
      instance (PrettyShow a, Show a) => PrettyShow (CompNode a)
        -- Defined at Interpreter.hs:61:10-58

問題はCompNode Intグラフではないことです。そのため、最初に一致したインスタンスがトリガーされるべきではないと思います。(2 つ目は実行したいものです。) 実際、引数がグラフであることを必要とする関数を作成すると、

> :{
| let g :: G.Graph a => a -> a
|     g = id
| :}

fでそれを呼び出すと、予想される no instance エラー メッセージが表示されます。

> g f

<interactive>:1:1:
    No instance for (G.Graph (CompNode Int))

事前に感謝します。クラウドソーシングで申し訳ありません。GHC 7.0.4 を使用しています。

4

1 に答える 1

4

問題は、CompNode Intがグラフではないため、最初に一致するインスタンスがトリガーされるとは思わないことです。

あなたはそう思うでしょうが、残念ながらそれはそのようには機能しません。

GHCがインスタンスを選択しているときは、先頭、つまりクラス名の後の部分のみを調べます。インスタンスの選択が行われた後でのみ、コンテキスト、つまりの前の部分が調べられます=>。コンテキストの不一致により、インスタンスが拒否され、タイプチェックエラーが発生する可能性がありますが、GHCがバックトラックして別のインスタンスを探すことはありません。

したがって、これらのインスタンスを考えると:

instance (G.Graph g, PrettyShow (G.Vertex g)) => PrettyShow g

instance (PrettyShow a, Show a) => PrettyShow (CompNode a)

...コンテキストを無視すると、次のようになります。

instance PrettyShow g

instance PrettyShow (CompNode a)

これにより、最初のインスタンスが完全に一般的であり、すべてと完全に重複していることが明確になります。

拡張機能を使用できる場合もありますがOverlappingInstances、それでも上記の動作は変わりません。むしろ、GHCは、存在する場合、一意に最も具体的なインスタンスを選択することにより、あいまいなインスタンスを解決できます。ただし、重複するインスタンスを使用するのは難しい場合があり、不可解なエラーが発生する可能性があるため、最初に設計を再考して、問題を完全に回避できるかどうかを確認することをお勧めします。

とは言うものの、ここでの特定の例でCompNode aは、確かに、のより明確な一致であるためCompNode Int、GHCは一般的なインスタンスの代わりにそれを選択します。

于 2011-07-25T02:00:22.590 に答える