Scalaで関数が明示的な戻り値の型を持つ必要があるのはなぜですか?


11

私は最近Scalaでプログラムすることを学び始めましたが、これまでのところ楽しかったです。私は、別の関数内で関数を宣言する機能が本当に好きです。

私がScalaについて抱えている問題の1つは、Scalaがその関数に明示的な戻り値の型を必要とするという事実です。そして、これは言語の表現力を妨げると感じています。また、その要件でプログラミングするのは難しいだけです。たぶん、私はJavascriptとRubyのコンフォートゾーンから来たからでしょう。しかし、Scalaのようにアプリケーションに大量の関数が接続されている言語の場合、自分が書いている特定の関数が再帰後に再帰で返されるタイプを正確に頭の中にブレーンストーミングする方法を考えることはできません。

関数の明示的な戻り値型宣言のこの要件は、JavaやC ++などの言語では気になりません。JavaとC ++の再帰は、実際に発生したときに、多くの場合2〜3個の関数で処理されていました。Scalaのように、いくつかの機能が連鎖することはありません。

だから私は、Scalaが明示的な戻り値の型を持つ関数の要件を持たなければならない正当な理由があるのだろうかと思いますか?


5
それはそうではありません-そして、もしそれが問題になったのなら、私はなぜそれを見るのに失敗します。
キーストンプソン

1
思った。Scalaで、関数の戻り値の型が実際にあいまいな場合はありますか?
ガベージコレクション

回答:


15

Scalaは、すべての関数で明示的な戻り値の型を必要とせず、単に再帰的な関数を返します。その理由は、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。それはスマート十分であれば、それは言うことができるほとんどは、戻り値の型がのスーパータイプであるということですList[Nothing]から、Nilその型のものです。それはの戻り値の型を正確に決定するのに十分な情報の近くにそれを与えませんmapInts

これはScalaに固有のものであり、より包括的な包括的型推論アルゴリズムを使用する静的に型付けされた他の言語(Miranda / Haskell / Cleanファミリーの大部分、MLファミリーの大部分、および散在する少数)があることに注意してくださいScalaが使用するよりも。また、これは完全にScalaのせいではないことに注意してください。名目上のサブタイピングとモジュール全体の型推論は基本的に互いに対立しています。Scalaの設計者は、Javaの互換性のために後者よりも前者を優先することを選択しました。反対の選択を念頭に置いて。


4
実際、問題は、より包括的な型推論アルゴリズムを考え出すことではありません。現在のScalaコンパイラーで高品質のエラーメッセージを維持しながら、より包括的な型推論アルゴリズムを考え出しています
ヨルグWミットタグ

1
case Nil実際には空の正しい戻り値ではないList[Int]()でしょうか?その場合、十分に賢いコンパイラーがそれを理解できます。しかし、それはすべて悪魔の擁護者を演じていると思います。
KChaloux
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.