新しいアカウントで始めました。

身の回りの出来事や写真が中心です。

F#イジってみました。Tourその15。RecursiveFunction。

2022-06-09 13:55:50 | F#

マイクロソフトのサイトから抜粋1

 要素のコレクションまたはシーケンスの処理は、通常、F# の再帰を使用して行われます。 F# では、ループや命令型プログラミングもサポートされていますが、正確性を保証するのが簡単であるため、再帰が推奨されます。

マイクロソフトのサイトから抜粋2

 F# では、末尾呼び出し最適化も完全にサポートされています。これは、再帰呼び出しを最適化して、ループ コンストラクトと同じ速度でできるようにするための方法です。

抜粋1、抜粋2共に、何を言ってるのか?(苦)理解できたのは、6の階乗だけ。


コメント (1)    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« F#イジってみました。Tourそ... | トップ | F#イジってみました。Tourそ... »
最新の画像もっと見る

1 コメント

コメント日が  古い順  |   新しい順
正確性、が何を意味してるかは知りませんが。 (cametan_42)
2022-06-09 18:37:06
> 末尾呼び出し

通常、再帰は例えば次のようなカンジでしょ?
みんな大好き、フィボナッチ数列だと、例えばOCamlでは

let rec fib n = match n with
  0 -> 0
 | 1 -> 1
 | n -> fib (n-1) + fib(n-2)

みたいに書きますよね?再帰呼び出ししてる。これがフツーの再帰、です。
一方、末尾再帰とは、再帰呼び出しした際に、その関数以外の関数、ないしは計算を一切使わないやり方です。
上の例だと再帰関数同士を「足し合わせてる」ので、これは末尾再帰じゃない。
一方、フィボナッチ数列は次のようにも書けます。

let fib n =
 let rec iter i a b = match i with
  0 -> a
 | _ -> iter (i - 1) b (a + b) in
 iter n 0 1;;

こっちのフィボナッチ数列はローカル関数(局所関数とも言う)iterを定義してますが、そこで再帰してます。
注目して欲しいのは関数iter内でiterを呼び出す際に、iter以外は呼び出してないし、それ以外の事をしてません。
こういうスタイルの再帰を末尾再帰、と言います。

SchemeもRacketもOCamlもF#も、原則、末尾再帰で再帰関数を書いた場合、内部的にはジャンプ構文に変換されます。そして再帰によるスタックの無駄遣いを起こしません。
こういう機能を末尾再帰最適化(TCO: Tail Call Optimization)と呼びます。
Microsoftが言ってるのは、F#で末尾再帰を書けば、それは効率良く.net上、つまり仮想マシン上でジャンプ構文に変換され、C#やVB.netでforループやwhileループを書くのと同じ効率を保証してる、って事です。
つまり「末尾再帰をガンガン使ってくれた方がF#らしいコードになるよ」って言ってるだけ、ですね。

反面、PythonなんかではTCOが実装/保証されてないので、メンド臭い、ってのは何度か指摘してる通りです。
返信する

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。

F#」カテゴリの最新記事