I need to make a function generator that iterates over an infinite sequence, like the fibonacci sequence. It should return the next value in the sequence when called. I am given a function prototype:
function genfib() {
return function fib() {
}
}
it should be used like this:
var fib = genfib();
fib(); // -> returns 0
fib(); // -> returns 1
fib(); // -> returns 1
fib(); // -> returns 2
I am confused about what is executing every time I call fib()
. I tried to do something like
function genfib() {
var count = 1;
if (count === 1) {
count++;
yield 0;
}
else if (count === 2) {
count++;
yield 1;
}
var a = 0;
var b = 1;
return function fib() {
while(1) {
count = a + b;
a = b;
b = count;
yield count;
}
}
}
But it's not working. I don't know how to set it up to run the if/else
for the first two numbers in the fib
sequence and then run the while
loop once for each subsequent call.
I need to make a function generator that iterates over an infinite sequence, like the fibonacci sequence. It should return the next value in the sequence when called. I am given a function prototype:
function genfib() {
return function fib() {
}
}
it should be used like this:
var fib = genfib();
fib(); // -> returns 0
fib(); // -> returns 1
fib(); // -> returns 1
fib(); // -> returns 2
I am confused about what is executing every time I call fib()
. I tried to do something like
function genfib() {
var count = 1;
if (count === 1) {
count++;
yield 0;
}
else if (count === 2) {
count++;
yield 1;
}
var a = 0;
var b = 1;
return function fib() {
while(1) {
count = a + b;
a = b;
b = count;
yield count;
}
}
}
But it's not working. I don't know how to set it up to run the if/else
for the first two numbers in the fib
sequence and then run the while
loop once for each subsequent call.
-
2
Do you know what
yield
does? – ncksllvn Commented Oct 30, 2014 at 4:40 - i think it's kind of like a return that only pauses a function instead of terminating it after returning a value – user137717 Commented Oct 30, 2014 at 4:42
-
2
If this is an assignment/homework (from "I am given a function prototype"), then it looks like you are supposed to learn about closures. Not write generators with
yield
. – Bergi Commented Oct 30, 2014 at 5:14 - If our answers have been helpful to you, please mark one one of the answers as correct. – ncksllvn Commented Oct 30, 2014 at 15:22
- 1 @user137717: Much the same :) But yes, that method stub is a definitive hint at using a closure. – Bergi Commented Oct 30, 2014 at 18:28
4 Answers
Reset to default 7If you want to use ES6 generators and yield
, then here's the approach:
function *fibonacci() {
var [prev, current] = [0, 1];
while (true) {
[prev, current] = [current, current+prev];
yield current;
}
}
One way to iterate over the results is with a for-of
loop:
for (var v of fibonacci()) {
console.log(v);
if (v > 100) break;
}
Note that the destructuring assignment var [prev, current] =
is supported in FF and Traceur but not in Chrome or node at present. If necessary rewrite it as:
function *fibonacci() {
var prev = 0, current = 1, oldprev;
while (true) {
oldprev = prev;
prev = current;
yield current += oldprev;
}
}
If you want the semantics of the function prototype you were given, then:
function genfib() {
var iterator = fibonacci();
return function fib() {
return iterator.next().value;
};
}
If you ask me, yield
has no place in this function, just some clever use of JavaScript closure.
You had the right idea in the beginning - you do need a function that returns a function. Outside of the inner function have a couple variables - one for the old, one for the next. Inside the function, all you have to do is calculate the new next
value, and then set old
to the next
's previous value. To switch their values, you'll need a placeholder variable.
function genfib() {
var next = 1
var old = 0
return function fib() {
var newNext= next + old
old = next
next = newNext
return next
}
}
var fib = genfib()
var result = []
for ( var i = 0; i < 10; i++ )
result.push( fib() )
document.body.innerHTML = result.join()
Of course, this doesn't account for the the first function call, which is a special case (1 should be returned twice.) But I'll leave that to you to figure out :-)
function* fib(num) {
var a = num, b = a + 1, c = a;
while (true) {
yield a;
c = a;
a = b;
b = c + b;
}
}
var it = fib(0);
console.log(it.next().value); // 0
console.log(it.next().value); // 1
console.log(it.next().value); // 1
console.log(it.next().value); // 2
console.log(it.next().value); // 3
console.log(it.next().value); // 5
console.log(it.next().value); // 8
console.log(it.next().value); // 13
For a high level overview on how to use generators, checkout this post.
function* fibonacci(){
var fn1 = 1;
var fn2 = 1;
while (true){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
var reset = yield current;
if (reset){
fn1 = 1;
fn2 = 1;
}
}
}
var sequence = fibonacci();
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next().value); // 13
console.log(sequence.next(true).value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3