次のプログラムを考えてみましょう。これは、一貫性のないインスタンスを有効にしてコンパイルするだけです。
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
main = do
print (g (undefined :: Int))
print (g (undefined :: Bool))
print (g (undefined :: Char))
data True
class CA t where
type A t; type A t = True
fa :: t -> String
instance CA Int where
fa _ = "Int"
class CB t where
type B t; type B t = True
fb :: t -> String
instance CB Bool where
fb _ = "Bool"
class CC t where
type C t; type C t = True
fc :: t -> String
instance CC Char where
fc _ = "Char"
class CAll t t1 t2 t3 where
g :: (t1 ~ A t, t2 ~ B t, t3 ~ C t) => t -> String
instance (CA t) => CAll t True t2 t3 where g = fa
instance (CB t) => CAll t t1 True t3 where g = fb
instance (CC t) => CAll t t1 t2 True where g = fc
一貫性のないインスタンスなしでコンパイルすると、複数のインスタンスが一致すると主張します。これは、一貫性のないインスタンスが許可されている場合、インスタンスが任意に選択されることを暗示しているように思われます。
非常に幸運でない限り、ほとんどの場合、インスタンスの制約が満たされないため、コンパイル エラーが発生します。
しかし、一貫性のないインスタンスではコンパイルエラーは発生せず、実際に「正しい」インスタンスが選択された次の出力が得られます。
"Int"
"Bool"
"Char"
したがって、ここでいくつかのことのいずれかを結論付けることができます。
- GHC は、インスタンス コンテキストの失敗を後戻りしています (独自のドキュメントには記載されていません)。
- GHC は一致するインスタンスが 1 つしかないことを実際に認識していますが、一貫性のないインスタンスをオンにしない限り、それを使用する勇気はありません。
- 私は非常に幸運でした (1/3 3 = 27 チャンス)
- 何か他のことが起こっています。
答えは 4 だと思います (おそらく 2 と組み合わせる)。ここで何が起こっているのかを説明する答えが欲しいのですが、一貫性のないインスタンスでこの動作にどれだけ頼ることができますか? 信頼できる場合、この動作を使用して非常に複雑なクラス階層を作成できるように思われます。これは、実際にはサブタイピングのように動作します。たとえば、クラス A とクラス B のすべての型がクラス C にあり、インスタンス ライターがインスタンスを作成できると言えます。 C のインスタンスを明示的に作成しなくても A.
編集:
答えはGHCのドキュメントでこれと関係があると思われます:
- ターゲット制約に一致するすべてのインスタンス I を見つけます。つまり、ターゲット制約は I の置換インスタンスです。これらのインスタンス宣言が候補です。
- 次の両方が成り立つ候補 IX を除外します。
- 厳密により具体的な IY 候補がもう 1 つあります。つまり、IY は IX の置換インスタンスですが、その逆ではありません。
- IX が重複可能であるか、または IY が重複しています。(「両方/および」の設計ではなく、この「どちらか/または」の設計により、クライアントは、ライブラリを変更する必要なく、ライブラリからインスタンスを意図的にオーバーライドできます。)
一貫性のない候補が 1 つだけ残っている場合は、それを選択します。残りの候補がすべて矛盾している場合は、任意の候補を選択します。そうでない場合、検索は失敗します (つまり、複数の生き残った候補が矛盾していない場合)。
(前のステップから) 選択された候補が矛盾している場合、検索は成功し、その候補が返されます。
そうでない場合は、ターゲットの制約と一致するが一致しないすべてのインスタンスを見つけます。このような非候補インスタンスは、ターゲット制約がさらにインスタンス化されたときに一致する可能性があります。それらのすべてが矛盾している場合、検索は成功し、選択された候補が返されます。そうでない場合、検索は失敗します。
間違っている場合は訂正してください。ただし、一貫性のないインスタンスが選択されているかどうかに関係なく、最初のステップでは「一致する」インスタンスは 1 つだけです。一貫性のないケースでは、ステップ 4 でその「一致した」ケースで失敗します。しかし、非一貫性のケースでは、ステップ 4 に進み、1 つのインスタンスのみが「一致」しているにもかかわらず、他のインスタンスが「統合」されていることがわかります。 . だから私たちは拒否しなければなりません。
この理解は正しいでしょうか?
もしそうなら、誰かが「一致」と「統一」の意味と、それらの違いを正確に説明できますか?