2016-05-12 18 views
10

私はES2015のジェネレータを理解しようとしており、それを使って再帰的階乗関数を作成しました。しかし、それは動作しません。私はトピックの上にthisのような既存の質問を参照しましたが、それは助けになりません。ES2015で再帰的ジェネレータ関数が機能しないのはなぜですか?

function* fact (n) { 
    if (n < 2) { 
    yield 1; 
    } else { 
    yield* (n * fact(n-1)); 
    } 
} 

let b = fact(5); 
console.log(b.next()); 

私はここで紛失している問題を見つけ出すことができますか?私はJavaScript-1.7でJSFiddleでこれを使用していますhere

+0

なぜ収量* 1を??? –

+0

私はそれが間違っていると思う。私にそれを更新させてください –

+0

あなたは何も返していません。あなたはこれが再帰呼び出しであると言っています。 –

答えて

7

私はここで紛失している明らかな問題を誰かが見つけることができますか?

factイテレータを返し、まだあなたはそれがで複数にしようとしている:n * fact(n-1)。それは動作しません!

factはイテレータを返すので、しかし、あなたはまた、nとイテレータの最後の値を乗算したい(すなわち、それは末尾再帰ではありません)、あなたはどちらかだけでyield*それをすることはできません。
あなたが値を再放出、明示的に内部の呼び出しから結果を反復処理する必要があり、最後の値を覚えて、それを持つことができます複数のように:あなたは末尾再帰する機能を変更した場合、それは、

function* fact (n) { 
    if (n < 2) { 
    yield 1; 
    } else { 
    let last; 
    for(last of fact(n-1)) { 
     yield last; 
    } 
    yield n * last; 
    } 
} 

Array.from(fact(5)); // [1, 2, 6, 24, 120] 

function* fact (n, acc=1) { 
    yield acc 
    if (n > 1) { 
    yield* fact(n-1, acc * n); 
    } 
} 
Array.from(fact(5)); // [1, 5, 20, 60, 120] 

を個人的に私は非再帰的に記述します。(私たちは、少なくともこの実装では、異なる順序で操作を実行するため)ビットが短く(およびよりよい)だろうが、結果も異なるだろうバージョン:

+0

2番目の尾の再帰バージョンは、探している。ありがとうございます:) –

+1

@Adityaジェネレータ関数はTCOの対象外であるため、テールコールは最適化されません。したがって、パフォーマンスの欠点と可能なスタックオーバーフローを考慮してください。 – rand

+0

@iven詳細を指摘してくれてありがとう –

2

210ちょうど目的の結果を返しますが、(フェリックスクリングの第二の例からわずかな変動)3つの引数を取り、別の末尾呼び出し再帰ソリューションを追加します

function *factorial(n, add=1, cnt=1) { 
    yield add; 
    if (cnt < n) { 
    cnt++; 
    yield* factorial(n, add * cnt, cnt); 
    } 
} 

Array.from(factorial(5)); 
// Array [ 1, 2, 6, 24, 120 ] 
関連する問題