2016-05-12 20 views
10

Sto cercando di capire i generatori in ES2015 e ho creato con esso una funzione fattoriale ricorsiva. Ma non funziona. Ho già fatto riferimento alla domanda esistente come this sull'argomento, ma non aiuta.Perché la funzione ricorsiva del generatore non funziona in ES2015?

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

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

Qualcuno può trovare problemi evidenti che mi mancano qui? Sto usando questo in JSFiddle con JavaScript-1.7 here

+0

Perché resa * 1 ??? –

+0

Ok. Penso che sia sbagliato. Consentimi di aggiornarlo –

+0

Non stai restituendo nulla .. e stai dicendo che questa è una chiamata ricorsiva. –

risposta

7

Qualcuno può trovare problemi evidenti che mi manca qui?

fact restituisce un iteratore, ma si stanno cercando di più con un numero di : n * fact(n-1). Non può funzionare!

Perché fact restituisce un iteratore, ma anche voi volete moltiplicare l'ultimo valore del iteratore con n (vale a dire che non è ricorsiva in coda), non si può semplicemente yield* esso sia.
Hai bisogno di iterare esplicitamente sul risultato della chiamata interna, reemit il valore e ricordare l'ultimo valore in modo da poter più con esso:

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] 

Se si modifica la funzione di essere ricorsiva in coda, si sarebbe un po 'più breve (e più), ma il risultato sarebbe anche diverso (poiché eseguiamo le operazioni in ordine diverso, almeno in questa implementazione):

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] 

Personalmente appena scrivere non ricorsiva versione:

function* fact (n) { 
    let result = 1; 
    let i = 0; 
    while (i < n) { 
    yield result = result * ++i; 
    } 
} 
Array.from(fact(5)); // [1, 2, 6, 24, 120] 
+0

La seconda versione ricorsiva della coda è la soluzione perfetta che ero cercando.Grazie mille :) –

+1

@Aditya La soluzione ricorsiva di coda non ottimizza le chiamate in coda, anche perché le funzioni del generatore non sono coperte dal TCO. Quindi considera gli svantaggi delle prestazioni e gli eventuali overflow dello stack. – rand

+0

@ thanks Grazie mille per aver sottolineato quel dettaglio –

2

solo aggiungere un'altra soluzione ricorsiva tail-chiamata che restituisce il risultato desiderato, ma richiede tre argomenti (una lieve variazione dal secondo esempio di Felix Kling):

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 ] 
Problemi correlati