型モデルはこのモデルにどのように適合しますか?
簡単な答えは、そうではありません。
強制、型クラス、またはアドホックポリモーフィズムのための他のメカニズムを言語に導入するときは常に、直面する主な設計上の問題は一貫性です。
基本的に、適切に型付けされたプログラムが単一の解釈を持つように、型クラスの解決が確定的であることを確認する必要があります。たとえば、同じスコープ内で同じ型の複数のインスタンスを指定できる場合、次のようなあいまいなプログラムを作成できます。
class Blah a where
blah : a -> String
instance Blah T where
blah _ = "Hello"
instance Blah T where
blah _ = "Goodbye"
v :: T = ...
main :: IO ()
main = print (blah v) -- does this print "Hello" or "Goodbye"?
コンパイラが作成するインスタンスの選択に応じて、またはのblah v
いずれ"Hello"
かに等しくなります"Goodbye"
。したがって、プログラムの意味はプログラムの構文によって完全に決定されるのではなく、コンパイラが行う任意の選択によって影響を受ける可能性があります。
この問題に対するHaskellの解決策は、各型が各型クラスに対して最大で1つのインスタンスを持つことを要求することです。これを確実にするために、トップレベルでのみインスタンス宣言を許可し、さらにすべての宣言をグローバルに表示します。これにより、曖昧なインスタンス宣言が行われた場合、コンパイラは常にエラーを通知できます。
ただし、宣言をグローバルに表示すると、セマンティクスの構成が崩れます。回復するためにできることは、プログラミング言語に精巧なセマンティクスを与えることです。つまり、Haskellプログラムをより適切に動作する、より構成的な言語に変換する方法を示すことができます。
これにより、実際にタイプクラスをコンパイルする方法も提供されます。これは通常、Haskellサークルでは「証拠変換」または「辞書渡し変換」と呼ばれ、ほとんどのHaskellコンパイラの初期段階の1つです。
型クラスは、プログラミング言語の設計が純粋な型理論とどのように異なるかの良い例でもあります。型クラスは本当に素晴らしい言語機能ですが、証明理論の観点から見ると、非常に悪い振る舞いをしています。(これが、Agdaがタイプクラスをまったく持たない理由であり、Coqがそれらをヒューリスティックな推論インフラストラクチャの一部にしている理由です。)