web-dev-qa-db-ja.com

Scalaで関数に明示的な戻り値の型が必要なのはなぜですか?

私は最近、Scalaでプログラミングの学習を始めましたが、今のところ楽しいです。私は、直感的に実行できるように見える別の関数内で関数を宣言する機能が本当に好きです。

Scalaは、Scalaがその関数に明示的な戻り値の型を必要とするという事実です)。このように言語の表現力を妨げます。また、その要件でプログラミングするのが難しいだけです。JavaScriptとRubyコンフォートゾーンから来たためかもしれません。しかしScalaアプリケーションには大量の接続された関数が含まれますが、書いている特定の関数が再帰後に再帰で返すべきタイプを正確に頭の中でブレインストーミングする方法を想像できません。

関数での明示的な戻り型宣言のこの要件は、JavaおよびC++などの言語では気になりません。JavaおよびC++での再帰は、発生した場合、多くの場合、最大2から3の関数が処理されましたが、Scalaのようにいくつかの関数が連鎖することはありません。

だから私はScalaが明示的な戻り値の型を持つ関数の要件を持つべきである理由があるのだろうか?

11

Scalaはall関数に明示的な戻り値の型を必要とせず、再帰的な関数を必要とします。その理由は、Scalaの型推論アルゴリズムは、先読みができない最初から最後までの単純なスキャン(に近いもの)であるためです。

つまり、次のような関数です。

def fortuneCookieJoke(message: String) = message + " in bed."

Scalaコンパイラは、ロジック変数を使用したり、メソッドのパラメータ以外を参照したりせずに、戻り値の型がStringであることが明確にわかるため、戻り値の型を必要としません。

一方、次のような関数:

def mapInts(f: (Int) => Int, l: List[Int]) = l match {
  case Nil => Nil
  case x :: xs => f(x) :: mapInts(f, xs)
}

Scalaコンパイラは、先読み変数または論理変数を使用しないと、mapIntsの型が正確に何であるかを正確に認識できないため、コンパイル時エラーが発生します。 Nilはその型であるため、戻り値の型はList[Nothing]のスーパータイプです。これは、mapIntsの戻り値の型を正確に判断するのに十分な情報を提供しません。

これはScalaに固有のものであり、はるかに包括的で有能な型推論アルゴリズムを使用する他の静的型付け言語(ほとんどのMiranda/Haskell/Cleanファミリー、ほとんどのMLファミリー、およびいくつかの分散型)があることに注意してくださいScalaが使用します。また、これは完全にScalaの責任ではないことに注意してください。公称サブタイピングとモジュール全体の型推論は基本的に互いに矛盾し、Scalaは、Java互換性のために、前者を後者よりも優先することを選択しましたが、「より純粋な」静的型付き関数型言語は、主に反対の選択を念頭に置いて設計されました。

15