Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoffeeScript: Using yield with recursion

I'm trying to understand how yield works with recursion. For example, we have the following function in CoffeeScript that computes the factorial of a positive integer and returns the current cumulative product:

prod = 1
f = (n) ->
  if n > 0
    prod = n * prod
    yield prod
    f(n-1)

So if we call this function with a = f(3) and stepping through a.next(), I expect to see something like

{value: 3, done: false} // prod = 3 * 1
{value: 6, done: false} // prod = 3 * 2
{value: 6, done: true}  // prod = 3 * 2 * 1

However, the actual output is

{value: 3, done: false}
{value: {}, done: false}
{value: undefined, done: true}
{value: undefined, done: true}
...

Could anyone explain what's going on here? And how I should change my code to get the desired results? Thanks!

like image 417
melonccoli Avatar asked Feb 24 '26 23:02

melonccoli


2 Answers

@phenomnomnominal, as of CoffeeScript 1.9.1, there is "yield from" for "yield*":

prod = 1
f = (n) ->
  if n > 0
    prod = n * prod
    yield prod
    yield from f(n-1)

gen = f(3)

loop
    ngen = gen.next()
    console.log ngen
    break if ngen.done

This should produce:

{ value: 3, done: false }
{ value: 6, done: false }
{ value: 6, done: false }
{ value: undefined, done: true }
like image 66
felixh Avatar answered Feb 26 '26 13:02

felixh


I got this to work with the following in JS, running in FireFox:

var prod = 1;
var f = function*(n) {
  if (n > 0) {
    prod = n * prod;
    yield prod;
    yield* f(n - 1);
  }
};

a = f(3);
console.log(a.next()); // Object { value: 3, done: false } 
console.log(a.next()); // Object { value: 6, done: false } 
console.log(a.next()); // Object { value: 6, done: false }
console.log(a.next()); // Object { value: undefined, done: true }

However, it looks as though CoffeeScript doesn't yet support yield*. Possibly a good chance for someone to contribute to the project! To get around this for now, you can use backticks to pass the JS through:

prod = 1
f = (n) ->
  if n > 0
    prod = n * prod
    yield prod
    `yield* f(n-1)`
like image 42
phenomnomnominal Avatar answered Feb 26 '26 13:02

phenomnomnominal