Can anyone find any obvious issues I am missing here?
fact
returns an iterator, yet you are trying to multiple it with a number: n * fact(n-1)
. That cannot work!
Because fact
returns an iterator, but you also want to multiply the last value of the iterator with n
(i.e. it is not tail-recursive), you cannot simply yield*
it either.
You need to explicitly iterate over the result from the internal call, reemit the value and remember the last value so that you can multiple with it:
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]
If you change the function to be tail-recursive, it would be a bit shorter (and nicer), but the result would also be different (since we perform the operations in different order, at least in this implementation):
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]
Personally I would just write a non-recursive version:
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]