2011-07-29 17 views
7

をフィボナッチ:http://rosettacode.org/wiki/Fibonacci_sequence#JavaScriptと、このプログラムを見た:末尾再帰と、私はこのサイトを見ていた

function fib(n) { 
    return function(n,a,b) { 
    return n>0 ? arguments.callee(n-1,b,a+b) : a; 
    }(n,0,1); 
} 

この作業を行う方法を、これら二つの引数(aとbの)助けは何ですか。私はそれをトレースし、それがまだどのように動作するのか分かりません。

答えて

9

ありますn + 1番目のフィボナッチ数(フィボナッチの実際のフィボナッチには2つの1があるため)。

例えば、N = 4:

n a b 
4 0 1 
3 1 2 
2 2 3 
1 3 5 
0 5 8 

あなたが見ることができるように、の値とフィボナッチ数にB常に等しいです。また、これはFunctional Programming(WebサイトSchemeプログラマー)と非常によく似ています。

1

abは、新たに定義された無名関数へのパラメータです。

このpageは、argumentsオブジェクトに関するドキュメントです。ドキュメンテーションのarguments.calleeは、あなたが現在使っている関数への参照です。これは無名関数で動作しているので、実際には名前はありません(彼らが知っている)。

彼らは(匿名で)深さがnと定義されている関数を再帰的に呼び出すようです。途中では、フィブス番号を計算しており、深度がnになると値aを返します。関数に渡された初期値はnnが0になったときに、次のようにaを有する、カウントダウンカウンタとして機能し、次の計算の目的のためにab記憶二つの連続するフィボナッチ数を、function(n,a,b)(n,0,1)

1

としてはhereを説明し、あなたがしている機能は、匿名あるのでarguments.calleeをは。あなたがしている現在の関数を指し、これは、関数を呼び出すと再帰を達成するための唯一の方法です。

特定の関数は、内部関数を再帰的に呼び出すことによってFibonacci sequenceを計算します。

1

aおよびbは、0および1から始まるシーケンスの現在の番号と次の番号を表します。 nはフィボナッチシーケンスのどの要素が返されるかを指定するカウントダウンタイマーです(EG:n = 1055を返します)。

この関数は、それが配列のn番目の数を計算することを意味引数nを受け入れることによって動作:

function fib(n) { 

コード次に、シーケンス内の次の数を計算する関数を定義する:

function(n,a,b) { 
    return n>0 ? arguments.callee(n-1,b,a+b) : a; 
} 

基本的に、この無名関数は、実行するたびにnを1ずつカウントダウンし、同時に、abをtの次の数字に移動します彼はシーケンス。 n0に等しい場合、シーケンスは完了し、現在の番号aが返されます。

arguments.calleeは、現在実行中の関数を参照しているため、コードは単に新しい引数でそれ自体をコールバックすることを意味します。言い換えれば、 "ループ"の次の反復を開始することです。

最後に、(n,0,1);というコードは、実際にfibに呼び出され、パラメータはn,0,1です。上記のスニペットから除外したreturnステートメントは、無名関数の戻り値をとり、fibの呼び出し元に返します。このように再帰を使用すると、テールコールの最適化を持たないJavaScriptなどの言語では効率的ではありません。大きいnの場合は、再帰の代わりに標準のループ構造を使用してこれを書いた方が良いでしょう。

+0

JavaScriptは最終的にES6以来のテールコールの最適化を持っています。http://benignbemine.github.io/2015/07/19/es6-tail-calls/ –

+0

言語がサポートしていますが、多くの実装はまだありません。https ://kangax.github。io/compat-table/es6/ –

-2

混乱を招くことがあるいくつかの問題があります。再帰関数パターンの短手と尾の最適化。

問題は、コードの簡略版にある可能性があります。以下の説明を明瞭にするために書かれています。

  1. それに名前を与えることによって、匿名関数を認める
  2. 条件(三)オペレータが拡大し、「再発」。

テール最適化は、アキュムレータ部分を追加することによって再帰関数のスタック使用を犠牲にするために使用されます。これは一般的なパターンですが、読みやすさにはなりません。これは、recur関数です。

ループ内での反復処理に比べてパフォーマンスが優れていることに特に注意してください。パラメータに関して

function fib(n) { 
 
    function recur(n, a, b) { 
 
     if (n > 0) { 
 
      return recur(n - 1, b, a + b); 
 
     } else { 
 
      return a; 
 
     } 
 
    } 
 
    return recur(n, 0, 1); 
 
}

NBはフィボナッチのシーケンスの一部である、反復カウンタです。

+0

これは機能をもっとはっきりさせていますが、元の質問には本当に答えません。あなたの答えを完成させるために、関数に関するいくつかの解説を加えてください。 – Brody

+0

それは良いですか? –

関連する問題