F#では、rec
キーワードを使用する必要があります。 Haskellでは、与えられた関数が再帰的であるかどうかを明示的に伝える必要はありません。
関数型プログラミングにおける再帰の役割を考えると、F#の設計はかなり奇妙に思えます。それは良い言語設計の決定ですか、それとも歴史的な理由のために、または実装の制約のために存在しますか?
HaskellとF#のセマンティクスには固有の違いがあります。 Haskellでは、関数呼び出しは実際の計算を実行しませんが、「サンク」と呼ばれるヒープオブジェクトを割り当てます。サンクがそれ自体または別のサンクへのリンクを持つことは完全に問題ありません。ただし、F#では、関数呼び出しは実際の呼び出しであり、let x = 1 : 2 : x in x
を構築する前にx
を構築する必要があるため、1 : 2 : x
のような式は無効になります。ただし、それは無限リストの多かれ少なかれ妥当な定義であり、それを定義する何らかの方法が存在する必要があります。ここにrec
のルートがあります。さらに必要な場合は、SMLとHaskellの運用上のセマンティクスを検索して読んでください。
これは SOで質問に回答済み であり、 "rec"が使用される理由についての強力な歴史的背景が含まれています.
後世の重要な引用は次のとおりです。
フランス語のCAML言語ファミリ(OCamlを含む)では、関数はデフォルトで再帰的ではありません。この選択により、新しい定義の本体内で以前の定義を参照できるため、これらの言語でletを使用して関数(および変数)の定義を簡単に置き換えることができます。 F#はOCamlからこの構文を継承しました。
再帰的なlet
は、通常のものよりもはるかに複雑なセマンティクスを定義します。したがって、単純さとクリーンな言語設計のために、両方を使用することには十分な理由があります。これは、Schemeでlet
、let*
、およびletrec
を個別に使用するのと同じです。
単純なlet x = y in z
は((fun x -> z) y)
と同等です。再帰的letははるかに複雑であり、固定小数点コンビネーターの使用を伴う場合があります。