1. ホーム
  2. f#

[解決済み] OCaml/F#の関数はなぜデフォルトで再帰的でないのですか?

2022-10-07 22:49:56

質問

F#やOCamlの関数が(おそらく他の言語も)デフォルトで再帰的でないのはなぜですか?

言い換えれば、なぜ言語設計者は、明示的にあなたが rec のような宣言で

let rec foo ... = ...

で、デフォルトで関数に再帰的な機能を与えないのですか? なぜ、明示的に rec を構成する必要があるのでしょうか?

どのように解決するのですか?

元のMLの子孫であるフランスやイギリスは異なる選択をし、その選択は何十年もかけて現代の変種に受け継がれています。ですから、これは単なるレガシーですが、これらの言語のイディオムに影響を及ぼしているのです。

フランスのCAML言語群(OCamlを含む)では、関数はデフォルトで再帰的ではありません。この選択により、関数(と変数)定義を let を使用した関数(および変数)の定義が容易になります。なぜなら、新しい定義の本文中で以前の定義を参照できるからです。F#はこの構文をOCamlから継承しています。

例えば、関数の上位にある p という関数に置き換えます。

let shannon fold p =
  let p x = p x *. log(p x) /. log 2.0 in
  let p t x = t +. p x in
  -. fold p 0.0

引数 p を高次の shannon 関数は、その上位にある別の p が本文の最初の行にあり、さらに別の p を本文の2行目に記述します。

逆に、ML言語群のイギリスSML支部は、もう一方の選択肢を取り、SMLの fun -の関数は,デフォルトで再帰的です.ほとんどの関数定義が,関数名の以前のバインディングにアクセスする 必要がない場合,これはより単純なコードになります.しかし,継承された関数が異なる名前( f1 , f2 など) を使用すると、スコープが汚染され、誤って間違った関数の "バージョン" を呼び出してしまう可能性があります。また、暗黙的に再帰的な fun -結合関数と非再帰的な val -バウンド関数です。

Haskellは、定義が純粋であることを制限することによって、定義間の依存関係を推測することを可能にしています。これにより、おもちゃのサンプルはよりシンプルに見えますが、他の部分で重大な犠牲を払っているのです。

GaneshとEddieが出した答えは、赤毛であることに注意してください。彼らは、なぜ関数のグループが巨大な let rec ... and ... の中に置くことができないのは、型変数が汎化されるときに影響するからだと説明しました。これは rec がSMLではデフォルトであるがOCamlではデフォルトでないこととは無関係です。