あなたの質問は、基本的に「スカラにはローカル型推論のみがあるのはなぜですか?」とか、あるいは「スカラに非ローカル型推論がないのはなぜですか?答えは、デザイナーが望んでいないからです。
これにはいくつかの理由があります。理由の1つは、ローカル型推論の最も妥当な代替案はグローバル型推論ですが、それはScalaでは不可能です:Scalaは別々のコンパイルとモジュール型のチェックを持っているので、コンパイラが全体を全体的に見ることはできませんプログラム。実際、Scalaには動的なコードのロードがあります。つまり、コンパイル時にコード全体がまだ存在する必要はありません。 Scalaでは、グローバルな型推論は単純に不可能です。私たちができることは、 "全体コンパイル単位型推論"ですが、それは望ましくないことです。型の注釈が必要かどうかは、コードを複数の単位でコンパイルするか1つだけコンパイルするかによって異なります。
もう1つの重要な理由は、モジュールの境界での型注釈が、型のための二重登録ブックのような二重チェックのように機能することです。言語でさえ、ハスケルのようなグローバル型の推論であっても、タイプ境界をモジュールの境界やパブリックインターフェイスに置くことが強く推奨されます。
第三の理由は、グローバルな型推論は時々代わり型注釈で失敗型チェッカの最後になるまで、それは、型inferencerは喜んで、ますます無意味タイプを推論沿っchugs場合、紛らわしいエラーメッセージをもたらすことができるということである実際のエラー(単純なタイプミスかもしれません)から離れた場所で、エラーサイトの元のタイプに接して接するだけのタイプエラーをあきらめます。これは、例えばHaskellで起こることがあります。 Scalaのデザイナーは有用なエラーメッセージを非常に重視し、良いエラーメッセージでそれらを実装する方法を理解できない限り、言語機能を犠牲にしています。 (でも、Scalaの非常に限られた型推論で、あなたは「Foo
はProduct with Serializable
を得た期待」のような「役に立つ」メッセージを取得できることに注意してください。)
をしかし、はこの例では何ができるかScalaのローカル型推論、働くことですあいまいなことができ、継承に基づいて、型パラメータを推測、あなたの特定の例
trait foo[F] {
def test: F
}
class ah extends foo[(Int, Int) ⇒ Int] {
def test = (i, j) ⇒ i + j
}
(new ah) test(2, 3) //=> 5
だからHindley-Milnerは 'test'の' foo'の型を推測することができますか? – slouc
Scalaには、H-Mがサポートしていないサブタイプがあります。 (多くの関数型言語とは異なり、Scalaの型システムはHMからかなり離れています)。しかし、グローバル型の推論を持つ仮説言語では、サブタイプ化や演算子のオーバーロードがなくても、ゼロ型アノテーションを持つすべての型を推論することができます。 ''と '' j 'で、無名関数の戻り値の型は '+'演算子の整数である(覚えておいてください:演算子のオーバーロードはありません)、 'test'の型を無名関数の関数型、 'test'の戻り値の型になります。おもう。 –
ええ、 'test'を推論するのに同意しましたが、' foo'の推論のためにその情報を使うことができるのだろうかと思っていました。 TBH私は、標準的なクラスのような構造がH-Mでサポートされているか許可されているか分からない(サブタイプの部分なしで、その型を返すメソッドを持つ単純な型パラメータ化されたクラス)。 – slouc