Haskellでタイプは消去されますか?


13

Haskellには、一般的なLispとの明らかな類似性を持つ「汎用関数」という概念があります。Haskellの経験も共通のLispの経験もないため、ここでは非常に近似するかもしれません。これは、to_stringすべてのタイプの文字列表現を定義する汎用機能を定義できることを意味します。もちろん、特別な場合にはto_string機能を定義する必要がありますが、シグネチャがの関数がありますα → string

OCamlのように、Haskellでもタイプは消去されますか?はいの場合、Haskellでの「ジェネリック関数」の実装は、型が動的であり、したがって消去されない一般的なLispの実装とどのように異なりますか?

実装の詳細はコンパイラ固有のものであることを理解していますが、おそらく多くまたはすべての実装に共通する規定があります。


5
typeの重要な関数を定義できないことを覚えておいてくださいa -> String。より多くの場合、型制約がありShow a => a -> Stringます。
DJG

回答:


16

これまでの答えは誤解を招くものです。

「パラメトリック」および「アドホックオーバーロード」ポリモーフィズムを区別する必要があります。パラメトリックとは、「すべてのタイプaに対して均一に動作する」ことを意味しますが、「アドホック」(サイモンがポリモーフィックと呼ぶもの)は、タイプに基づいて実装を変更します。

両方の例はreverse :: [a] -> [a]、パラメータであり、show :: Show a => a -> String「アドホック」過負荷です。

もっと抽象的な直観が必要な場合は、オブジェクトに制約を課さない「所有する」や「考える」など、すべてのオブジェクトに対して「機能する」自然言語動詞のクラスを検討すると役立つと思いますが、 「開く」には、話している内容を開くことができる必要があります。たとえば「木を開ける」のは意味がありませんが、「ドアを考える」、「ドアを開ける」ことができます。さらに例を挙げると、「開く」とは「アドホックポリモーフィック」であり、「ウィンドウを開く」と「カスタマーサービスで苦情チケットを開く」はまったく異なるものです。これが強制されているようであれば、忘れてください!わたしにはできる。

ただし、どちらもコンパイル時に解決され、実際には「消去」されます。ModuloのさまざまなGHC拡張機能やTemplate Haskellなど。型実際にはコンパイル時に消去され、実行時には検査されません。

パラメトリック多相関数は、すべての型で同じように動作するため、生成する必要があるコードは1つだけです。一方、コンパイラは、コンパイル時に特定のプログラムポイントで実行する「型クラス」関数のバージョンを決定します。これが、タイプクラスごとのタイプごとに1つのインスタンスの制限と、対応する「newtype」回避策が存在する理由でもあります。

実装の詳細については、SPJの教科書と、Wadler and Blottsの型クラスに関するペーパーを参照してください


私の答えを削除すべきだと思いますか?
サイモンベルゴ

いいえ、正確な語彙に当たらないという警告は問題ありません:)
クリス

GHCがタイプを消去することができる理由を少し拡大していただけますか?プリンシパルタイピングのおかげですか?
サイモンベルゴ

2
一般に、実行時に、パラメータポリモーフィック関数は1回だけ存在し、仮想ディスパッチメソッドを介してアドホックポリモーフィック関数を呼び出すか、タイプごとにすべてのコードを個別に生成し、静的にリンクします。どちらの実装も言語の観点からは正しいです(Haskellにはポリモーフィック型がないため、そのようなものはGHC forall拡張機能でのみ作成できることに注意してください)。
Jan Hudec

型の消去を許可しないGHC拡張機能はありますか?オーバーロードは静的であり、完全な依存型がないため、何も考えられません
ダニエルグラッツァー

1

警告:CSでの私のバックグラウンドはあまり強くないので、常に正しい語彙を使うとは限らず、いくつかの点で間違っているかもしれません。とにかく、ここに私の理解があります:

ジェネリックとポリモーフィズムを混同していると思います。

などの汎用タイプList<Foo>は、他のタイプをパラメーターとしてとるタイプを記述するために使用され、より豊富なタイプチェックを可能にします。

haskellの汎用関数は次のようになりますcount:: List a -> Int。任意のタイプのリストを受け入れ、要素の数を返します。実装は1つだけです。

通常、リストを定義するとき、Tについて何も仮定できません。それを保存して返すだけです。

あなたのto_string機能は、異なる状況下で異なる動作をすることを意味ポリモーフィック機能、です。haskellでは、これは型の形容詞のように機能する型クラスで行われます。

関数Showを定義するタイプクラスがありますshow :: a -> String

FooShowtypeclassを実装する場合、の定義を提供する必要がありますshow。このタイプは、Show修飾子を必要とする関数で使用できます(などShow a => a -> whatever)。Haskellは型を消去できません。これらの関数は関数の正しい実装を見つける必要があるためshowです。


Common Lispでは、ポリモーフィック関数は「ジェネリック関数」IIRCと呼ばれ、私は同じ(紛らわしい)語彙を使用しました。あなたの答えは役に立ち、あなたの最後の議論はかなり説得力があります。.-)
user40989

「実装は1つだけです」-理にかなっているのは1つだけですが、可能性は無限にあります。タイプa→bの関数には| b | ^ | a |があります 可能な実装(タイプBool→Boolの関数の数を考慮)、およびリストにはサイズの上限はありません。
ジョンパーディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.