最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why recursive generator function doesn't work in ES2015? - Stack Overflow

programmeradmin4浏览0评论

I am trying to understand generators in ES2015 and have created a recursive factorial function with it. But it doesn't work. I have referred already existing question like this on the topic, but it doesn't help.

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

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

Can anyone find any obvious issues I am missing here? I am using this in JSFiddle with JavaScript-1.7 here

I am trying to understand generators in ES2015 and have created a recursive factorial function with it. But it doesn't work. I have referred already existing question like this on the topic, but it doesn't help.

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

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

Can anyone find any obvious issues I am missing here? I am using this in JSFiddle with JavaScript-1.7 here

Share Improve this question edited May 23, 2017 at 10:29 CommunityBot 11 silver badge asked May 12, 2016 at 6:23 Aditya SinghAditya Singh 16.7k15 gold badges48 silver badges69 bronze badges 13
  • Ok. I think that's wrong. Let me update it – Aditya Singh Commented May 12, 2016 at 6:31
  • You are not returning anything.. and you are saying that this is a recursive call. – Rajaprabhu Aravindasamy Commented May 12, 2016 at 6:31
  • Yeah. With yield you don't need to return. Refer: 2ality./2013/06/iterators-generators.html – Aditya Singh Commented May 12, 2016 at 6:32
  • Why does he need to return anything? – user663031 Commented May 12, 2016 at 6:33
  • 1 fact returns an iterator. What do you expect the result of multiplying a number with an iterator (n * fact(n-1)) to be? – Felix Kling Commented May 12, 2016 at 6:33
 |  Show 8 more ments

2 Answers 2

Reset to default 9

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]

Just to add another tail-call recursive solution that returns the desired result, but takes three arguments (a slight variation from Felix Kling's second example):

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 ]
发布评论

评论列表(0)

  1. 暂无评论