Now that ES6 supports Proper Tail Call, and since according to Wikipedia, "In any language which supports closures and proper tail calls, it is possible to write programs in continuation-passing style and manually implement call/cc.", we should be able to properly implement call/cc in JavaScript, without using tricks to empty the call stack.
(EDIT: sadly, most web browsers don't support PTC, but we can still use the tricks described in that question)
According to this article, it should look like this:
function callcc (f,cc) {
f(function(x,k) { cc(x) },cc)
}
As I tried to understand continuations and their usecases, I wanted to implement the second example in call/cc's page on Wikipedia in JavaScript, but failed:
;; [LISTOF X] -> ( -> X u 'you-fell-off-the-end)
(define (generate-one-element-at-a-time lst)
;; Both internal functions are closures over lst
;; Internal variable/Function which passes the current element in a list
;; to its return argument (which is a continuation), or passes an end-of-list marker
;; if no more elements are left. On each step the function name is
;; rebound to a continuation which points back into the function body,
;; while return is rebound to whatever continuation the caller specifies.
(define (control-state return)
(for-each
(lambda (element)
(set! return (call-with-current-continuation
(lambda (resume-here)
;; Grab the current continuation
(set! control-state resume-here)
(return element))))) ;; (return element) evaluates to next return
lst)
(return 'you-fell-off-the-end))
;; (-> X u 'you-fell-off-the-end)
;; This is the actual generator, producing one item from a-list at a time.
(define (generator)
(call-with-current-continuation control-state))
;; Return the generator
generator)
(define generate-digit
(generate-one-element-at-a-time '(0 1 2)))
(generate-digit) ;; 0
(generate-digit) ;; 1
(generate-digit) ;; 2
(generate-digit) ;; you-fell-off-the-end
How would you do it?
Is it even possible?
(EDIT: as explained in the comments, this is not a duplicate of call/CC with closures, which is about implementing call/cc in JS; my question is about implementing the Wikipedia example in JS assuming that call/cc is already implemented (with or without tricks to empty the call stack), which is not trivial)
EDIT: Here is my final working JS implementation, thanks to that answer and its comments, which put me in the right direction:
const callcc = (f,cc) => { f(cc,cc) }
const forEach = (f, lst, cc) => {
const partialForEach = (f, lst, start, cc) => {
if (start === lst.length) {
cc();
} else {
f(lst[start], () => partialForEach(f, lst, start+1, cc));
}
}
partialForEach(f, lst, 0, cc)
};
const generate_one_element_a_time = lst => {
let control_state = (ret) => {
forEach(
(element, cc) => {
callcc(
(resume_here) => {
control_state = resume_here
ret(element)
},
c => {
ret = c
cc()
}
)
},
lst,
() => ret("you-fell-off-the-end")
)
}
let generator = (cc) => {
callcc(control_state, cc)
}
return generator
}
const generate_digit = generate_one_element_a_time([0,1,2])
generate_digit(console.log) // 0
generate_digit(console.log) // 1
generate_digit(console.log) // 2
generate_digit(console.log) // you-fell-off-the-end
This code:
(define (sum-even n)
(call/cc (lambda (exit)
(let loop ((n n))
(cond ((= n 0) 0)
((< n 0) (exit 0))
(else (+ n (loop (- n 2)))))))))
(sum-even 6) ; ==> 12
(sum-even 5) ; ==> 0
So the two first uses never actually uses the continuation, but what happens is that you have this in the first (+ 6 (+ 4 (+ 2 0))) while in the second we have (+ 5 (+ 3 (+ 1 (exit 0)))) and the inner expression just kills the rest of the calculations. That is the whole purpose of call/cc.
Same in JavaScript:
const sumEven = (n) => {
callCc((exit) => {
const loop = (n) => {
if (n === 0) {
return 0;
} else if (n < 0) {
exit(0);
} else {
return n + loop(n - 2);
}
};
return loop(n);
});
};
sumEven(6); // 12 because 6 + 4 + 2 + 0
sumEven(5); // 0 because 5 + 3 + 1 + exit(0)
That doesn't work since JavaScipt doesn't provide callCc. The second best would be to use rewrite it to CPS:
const callCCK = (f, k) => f((v, ignoredK) => k(v), k);
const sumEvenK = (n, ek) => {
callCCK((exitK, k) => {
const loopK = (n, k) => {
if (n === 0) {
k(0);
} else if (n < 0) {
exitK(0, k);
} else {
loopK(n - 2, loopResult => k(n + loopResult));
}
};
loopK(n, k);
}, ek);
}
sumEvenK(6, v => console.log(v)); // prints 12
sumEvenK(5, v => console.log(v)); // prints 0
When your code already is in CPS using callCc isn't really needed since instead we could write it like this:
const sumEvenK = (n, ek) => {
const loopK = (n, k) => {
if (n === 0) {
k(0);
} else if (n < 0) {
ek(0);
} else {
loopK(n - 2, loopResult => k(n + loopResult));
}
};
loopK(n, ek);
}
sumEvenK(6, v => console.log(v)); // prints 12
sumEvenK(5, v => console.log(v)); // prints 0
Since again, the whole reason why we have call/cc in Scheme is to get the power of CPS without having to write the tedious CPS.
So there you go. You need to rewrite your generateOneElementAtATime into CPS so that it can use the CPS version of your callcc. Good luck!
I've been playing around with Haskell and find it fascinating, especially the Lazy Evaluation feature which allows us to work with (potencially) infinite lists.
From this, derives the beautiful implementation of the Sieve of Eratosthenes to get an infinite list of primes:
primes = sieve [2..]
where sieve (x:xs) = x : sieve [i | i <- xs, i `mod` x /= 0]
Still using haskell i can have either:
takeWhile (<1000) primes
which gives me the primes until 1000 (n), or
take 1000 primes
which gives me the first 1000 primes
I tried to implement this in Javascript, forgetting the 'infinite' possibility and this is what i came up with:
const sieve = list => {
if (list.length === 0) return []
const first = list.shift()
const filtered = list.filter(x => x % first !== 0)
return [first, ...sieve(filtered)]
}
const getPrimes = n => {
const list = new Array(n - 1).fill(null).map((x, i) => i + 2)
return sieve(list)
}
It works perfectly (if i don't reach maximum call stack size), but i can only get the prime numbers "up until" n.
How could i use this to implement a function that would instead return "the first n" primes?
I've tried many approaches and couldn't get it to work
Bonus
is there any way i can use tail call optimization or something else to avoid StackOverflows for large Ns?
As #VLAZ suggested, we can do this using generators:
function* removeMultiplesOf(x, iterator) {
for (const i of iterator)
if (i % x != 0)
yield i;
}
function* eratosthenes(iterator) {
const x = iterator.next().value;
yield x;
yield* eratosthenes(removeMultiplesOf(x, iterator));
}
function* from(i) {
while (true)
yield i++;
}
function* take(n, iterator) {
if (n <= 0) return;
for (const x of iterator) {
yield x;
if (--n == 0) break;
}
}
const primes = eratosthenes(from(2));
console.log(Array.from(take(1000, primes)));
Btw, I thought one might be able to optimise this by not doing division repeatedly:
function* removeMultiplesOf(x, iterator) {
let n = x;
for (const i of iterator) {
while (n < i)
n += x;
if (n != i)
yield i;
}
}
but a quick benchmark showed it actually is about as fast as the simple function.
Alright, after working all weekend on this, i think i found my best implementation.
My solution uses proper caching (using the power of closures) of previous results so, the performance keeps getting better the more you use it
To get the first N primes, I iterate through the getPrimesTill until i reach a sufficient length... there is a compromise here, which will find more primes than intended on the first time but i don't think it can be any other way. Maybe getPrimesTill(n + ++count * n * 5) can be further optimized but i think this is more than good enough.
To be able to handle very large numbers while avoiding stack overflows, i implemented the sieve algorithm using a for loop, instead of recursion.
Here's the code:
function Primes() {
let thePrimes = []
const shortCircuitPrimes = until => {
const primesUntil = []
for (let i = 0; ; i++) {
if (thePrimes[i] > until) {
return primesUntil
}
primesUntil.push(thePrimes[i])
}
}
const sieveLoop = n => {
const list = buildListFromLastPrime(n)
const result = []
let copy = [...thePrimes, ...list]
for (let i = 0; i < result.length; i++) {
copy = copy.filter(x => x % result[i] !== 0)
}
for (let i = 0; ; i++) {
const first = copy.shift()
if (!first) return result
result.push(first)
copy = copy.filter(x => x % first !== 0)
}
}
const buildListFromLastPrime = n => {
const tpl = thePrimes.length
const lastPrime = thePrimes[tpl - 1]
const len = n - (lastPrime ? tpl + 1 : 1)
return new Array(len).fill(null).map((x, i) => i + 2 + tpl)
}
const getPrimesTill = n => {
const tpl = thePrimes.length
const lastPrime = thePrimes[tpl - 1]
if (lastPrime > n) {
return shortCircuitPrimes(n)
}
const primes = sieveLoop(n)
if (primes.length - thePrimes.length) {
thePrimes = primes
}
return primes
}
const getFirstPrimes = n => {
let count = 0
do {
if (thePrimes.length >= n) {
return thePrimes.slice(0, n)
}
getPrimesTill(n + ++count * n * 5)
} while (true)
}
return { getPrimesTill, getFirstPrimes, thePrimes }
}
const { getPrimesTill, getFirstPrimes, thePrimes } = Primes()
I created a repo for it, with exhaustive testing anyone wants to give it a go.
https://github.com/andrepadez/prime-numbers-sieve-eratosthenes-javascript
The entire test suite takes about 85s to run, as i'm testing with many possible combinations and very large numbers.
Also, all the expected results were obtained from the Haskell implementation, so to not to pollute the tests.
Also, I found this awesome video, where the guy implements Lazy Evaluation and Infinite Lists using TypeScript... In the end, he builds the Sieve Algorithm in Javascript, working exactly like intended in Haskell
https://www.youtube.com/watch?v=E5yAoMaVCp0
All those generators have been available for a while within prime-lib:
Get the first 10 primes:
import {generatePrimes, stopOnCount} from 'prime-lib';
const i = generatePrimes(); // infinite primes generator
const k = stopOnCount(i, 10); // the first 10 primes
console.log(...k); //=> 2 3 5 7 11 13 17 19 23 29
Get all primes between 1000 and 1100:
import {generatePrimes, stopOnValue} from 'prime-lib';
const i = generatePrimes({start: 1000});
const k = stopOnValue(i, 1100);
console.log(...k); //=> 1009 1013 ... 1093 1097
...etc., plenty of examples within the library itself.
P.S. I am the author.
Mind the following function:
function count(n) {
if (n === 0) {
return 0;
} else {
return 1 + count(n - 1);
}
}
It is the simplest recursive function that counts from 0 to N. Since JavaScript has a small stack limit, that function easily overflows. In general, any recursive function can be converted in one that uses a manual stack and, thus, can't stack overflow; but doing so is complex. Is it possible, for the general case, to convert a JavaScript recursive function in one that uses its own stack, without using a continuation-passing style? In other words, suppose we had written:
const count = no_overflow(function(count) {
return function(n) {
if (n === 0) {
return 0;
} else {
return 1 + count(n - 1);
}
}
});
Is it possible to implement no_overflow in such a way that this new count function is equivalent to the old one, except without stack overflows?
Notes:
This is not about tail call optimization, since no_overflow should work for non-tail-recursive functions.
Trampolining is not helpful since, for the general case, it requires the function to be written in a continuation-passing style, which it isn't.
Writing the function with yield doesn't work either for a similar reason: you can't yield from inner lambdas.
That no_overflow would, essentially, work like a stack-free Y-combinator.
In JavaScript, calling a function f(x, y, ...) subjects us to the underlying implementation details of the stack and frames. If you recur using function application, you will absolutely, unavoidably run into a stack overflow.
However, if we can adopt a slightly different notation, such as call(f, x, y, ...), we can control function application however we want -
const add1 = x =>
x + 1
const count = (n = 0) =>
n === 0
? 0
: call(add1, call(count, n - 1)) // <-- count not in tail pos
console.log(noOverflow(count(99999)))
// 99999
Implementing noOverflow is a wrapper around loop, defined in this Q&A -
const noOverflow = t =>
loop(_ => t)
Unsurprisingly this is a non-trivial problem but the answer(s) there should help detail the things you have to consider and some good test cases, should you choose to implement a solution of your own.
Expand the snippet below to verify the results in your browser -
const call = (f, ...values) =>
({ type: call, f, values })
const recur = (...values) =>
({ type: recur, values })
const identity = x =>
x
const loop = (f) =>
{ const aux1 = (expr = {}, k = identity) =>
expr.type === recur
? call (aux, expr.values, values => call (aux1, f (...values), k))
: expr.type === call
? call (aux, expr.values, values => call (aux1, expr.f (...values), k))
: call (k, expr)
const aux = (exprs = [], k) =>
call
( exprs.reduce
( (mr, e) =>
k => call (mr, r => call (aux1, e, x => call (k, [ ...r, x ])))
, k => call (k, [])
)
, k
)
return run (aux1 (f ()))
}
const run = r =>
{ while (r && r.type === call)
r = r.f (...r.values)
return r
}
const noOverflow = t =>
loop(_ => t)
const add1 = x =>
x + 1
const count = (n = 0) =>
n === 0
? 0
: call(add1, call(count, n - 1))
console.log(noOverflow(count(99999)))
// 99999
I've been trying to translate this recursive Haskell implementation of a futumorphism specialized to Lists
futuL :: (a -> Maybe (b, ([b], Maybe a))) -> a -> [b]
futuL f x = case f x of
Nothing -> []
Just (y, (ys, mz)) -> y : (ys ++ fz)
where fz = case mz of
Nothing -> []
Just z -> futuL f z
into an imperative Javascript loop. It is remarkably difficult (at least for me):
const None = ({type: "Option", tag: "None"});
const Some = x => ({type: "Option", tag: "Some", runOption: x});
const arrFutu = coalg => x => { // futuL f x
const acc = []; // ~ fz
while (true) {
let optX = coalg(x); // f x
switch (optX.tag) { // case
case "None": return acc; // Nothing -> []
case "Some": {
let [y, [ys, optX_]] = optX.runOption; // Just (y, (ys, mz))
switch(optX_.tag) {
case "None": {
arrPushFlat(acc) ((ys.unshift(y), ys)); // y : (ys ++ [])
return acc;
}
case "Some": { // y : (ys ++ futuL f z)
arrPushFlat(acc) ((ys.unshift(y), ys));
x = optX_.runOption;
break;
}
default: throw new UnionError("invalid tag");
}
break;
}
default: throw new UnionError("invalid tag");
}
}
};
I have a difficult time to parse the Haskell code mentally, especially the where part containing the recursive call. I guess this call isn't in tail position, therefore I need an explicit stack (acc) for my JS loop.
Is my translation correct?
Because Haskell is lazy, one can start consuming the beginning of the list returned by the "futu" before the rest has been calculated. In Javascript terms, this is best modeled with generators.
For example (for simplicity, I used null values to represent the Nones):
const arrFutu = coalg => function*(seed) {
while (true) {
const next = coalg(seed);
if (next) {
// Maybe (b, ([b], Maybe a)), using null for None & flattening nested tuple
const [item, items, nextseed] = next;
yield item;
yield* items;
// Maybe a, using null for None
if (nextseed) {
seed = nextseed;
continue; // Continue iterating if the seed isn't null.
}
}
return;
}
}
With an example coalgebra like:
const coalg1 = seed => {
if (seed < 5) {
return ['a', ['a','a'], seed + 1];
} else if (seed < 10) {
return ['b', ['b','b'], seed + 1];
} else if (seed == 10) {
return ['c', ['c'], null];
}
return null;
}
for (const x of arrFutu(coalg1)(0)) {
console.log(x);
}
for (const x of arrFutu(coalg1)(20)) {
console.log(x);
}
It would be nice to make the futu recursive instead of iterative, but it seems Javascript tail call optimization doesn't work with generators.
By the way, even if the Haskell code isn't tail recursive, the recursion is "guarded": the recursive call happens within one or more data constructors (here, list constructors) and the call can be delayed until the constructors have been "peeled away" by the client when he is consuming the returned list.
The typical way to loop x times in JavaScript is:
for (var i = 0; i < x; i++)
doStuff(i);
But I don't want to use the ++ operator or have any mutable variables at all. So is there a way, in ES6, to loop x times another way? I love Ruby's mechanism:
x.times do |i|
do_stuff(i)
end
Anything similar in JavaScript/ES6? I could kind of cheat and make my own generator:
function* times(x) {
for (var i = 0; i < x; i++)
yield i;
}
for (var i of times(5)) {
console.log(i);
}
Of course I'm still using i++. At least it's out of sight :), but I'm hoping there's a better mechanism in ES6.
Using the ES2015 Spread operator:
[...Array(n)].map()
const res = [...Array(10)].map((_, i) => {
return i * 10;
});
// as a one liner
const res = [...Array(10)].map((_, i) => i * 10);
Or if you don't need the result:
[...Array(10)].forEach((_, i) => {
console.log(i);
});
// as a one liner
[...Array(10)].forEach((_, i) => console.log(i));
Or using the ES2015 Array.from operator:
Array.from(...)
const res = Array.from(Array(10)).map((_, i) => {
return i * 10;
});
// as a one liner
const res = Array.from(Array(10)).map((_, i) => i * 10);
Note that if you just need a string repeated you can use String.prototype.repeat.
console.log("0".repeat(10))
// 0000000000
OK!
The code below is written using ES6 syntaxes but could just as easily be written in ES5 or even less. ES6 is not a requirement to create a "mechanism to loop x times"
If you don't need the iterator in the callback, this is the most simple implementation
const times = x => f => {
if (x > 0) {
f()
times (x - 1) (f)
}
}
// use it
times (3) (() => console.log('hi'))
// or define intermediate functions for reuse
let twice = times (2)
// twice the power !
twice (() => console.log('double vision'))
If you do need the iterator, you can use a named inner function with a counter parameter to iterate for you
const times = n => f => {
let iter = i => {
if (i === n) return
f (i)
iter (i + 1)
}
return iter (0)
}
times (3) (i => console.log(i, 'hi'))
Stop reading here if you don't like learning more things ...
But something should feel off about those...
single branch if statements are ugly — what happens on the other branch ?
multiple statements/expressions in the function bodies — are procedure concerns being mixed ?
implicitly returned undefined — indication of impure, side-effecting function
"Isn't there a better way ?"
There is. Let's first revisit our initial implementation
// times :: Int -> (void -> void) -> void
const times = x => f => {
if (x > 0) {
f() // has to be side-effecting function
times (x - 1) (f)
}
}
Sure, it's simple, but notice how we just call f() and don't do anything with it. This really limits the type of function we can repeat multiple times. Even if we have the iterator available, f(i) isn't much more versatile.
What if we start with a better kind of function repetition procedure ? Maybe something that makes better use of input and output.
Generic function repetition
// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
if (n > 0)
return repeat (n - 1) (f) (f (x))
else
return x
}
// power :: Int -> Int -> Int
const power = base => exp => {
// repeat <exp> times, <base> * <x>, starting with 1
return repeat (exp) (x => base * x) (1)
}
console.log(power (2) (8))
// => 256
Above, we defined a generic repeat function which takes an additional input which is used to start the repeated application of a single function.
// repeat 3 times, the function f, starting with x ...
var result = repeat (3) (f) (x)
// is the same as ...
var result = f(f(f(x)))
Implementing times with repeat
Well this is easy now; almost all of the work is already done.
// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
if (n > 0)
return repeat (n - 1) (f) (f (x))
else
return x
}
// times :: Int -> (Int -> Int) -> Int
const times = n=> f=>
repeat (n) (i => (f(i), i + 1)) (0)
// use it
times (3) (i => console.log(i, 'hi'))
Since our function takes i as an input and returns i + 1, this effectively works as our iterator which we pass to f each time.
We've fixed our bullet list of issues too
No more ugly single branch if statements
Single-expression bodies indicate nicely separated concerns
No more useless, implicitly returned undefined
JavaScript comma operator, the
In case you're having trouble seeing how the last example is working, it depends on your awareness of one of JavaScript's oldest battle axes; the comma operator – in short, it evaluates expressions from left to right and returns the value of the last evaluated expression
(expr1 :: a, expr2 :: b, expr3 :: c) :: c
In our above example, I'm using
(i => (f(i), i + 1))
which is just a succinct way of writing
(i => { f(i); return i + 1 })
Tail Call Optimisation
As sexy as the recursive implementations are, at this point it would be irresponsible for me to recommend them given that no JavaScript VM I can think of supports proper tail call elimination – babel used to transpile it, but it's been in "broken; will reimplement" status for well over a year.
repeat (1e6) (someFunc) (x)
// => RangeError: Maximum call stack size exceeded
As such, we should revisit our implementation of repeat to make it stack-safe.
The code below does use mutable variables n and x but note that all mutations are localized to the repeat function – no state changes (mutations) are visible from outside of the function
// repeat :: Int -> (a -> a) -> (a -> a)
const repeat = n => f => x =>
{
let m = 0, acc = x
while (m < n)
(m = m + 1, acc = f (acc))
return acc
}
// inc :: Int -> Int
const inc = x =>
x + 1
console.log (repeat (1e8) (inc) (0))
// 100000000
This is going to have a lot of you saying "but that's not functional !" – I know, just relax. We can implement a Clojure-style loop/recur interface for constant-space looping using pure expressions; none of that while stuff.
Here we abstract while away with our loop function – it looks for a special recur type to keep the loop running. When a non-recur type is encountered, the loop is finished and the result of the computation is returned
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = $n => f => x =>
loop ((n = $n, acc = x) =>
n === 0
? acc
: recur (n - 1, f (acc)))
const inc = x =>
x + 1
const fibonacci = $n =>
loop ((n = $n, a = 0, b = 1) =>
n === 0
? a
: recur (n - 1, b, a + b))
console.log (repeat (1e7) (inc) (0)) // 10000000
console.log (fibonacci (100)) // 354224848179262000000
for (let i of Array(100).keys()) {
console.log(i)
}
Here is another good alternative:
Array.from({ length: 3}).map(...);
Preferably, as #Dave Morse pointed out in the comments, you can also get rid of the map call, by using the second parameter of the Array.from function like so:
Array.from({ length: 3 }, () => (...))
I think the best solution is to use let:
for (let i=0; i<100; i++) …
That will create a new (mutable) i variable for each body evaluation and assures that the i is only changed in the increment expression in that loop syntax, not from anywhere else.
I could kind of cheat and make my own generator. At least i++ is out of sight :)
That should be enough, imo. Even in pure languages, all operations (or at least, their interpreters) are built from primitives that use mutation. As long as it is properly scoped, I cannot see what is wrong with that.
You should be fine with
function* times(n) {
for (let i = 0; i < n; i++)
yield i;
}
for (const i of times(5)) {
console.log(i);
}
But I don't want to use the ++ operator or have any mutable variables at all.
Then your only choice is to use recursion. You can define that generator function without a mutable i as well:
function* range(i, n) {
if (i >= n) return;
yield i;
return yield* range(i+1, n);
}
times = (n) => range(0, n);
But that seems overkill to me and might have performance problems (as tail call elimination is not available for return yield*).
I think it is pretty simple:
[...Array(3).keys()]
or
Array(3).fill()
const times = 4;
new Array(times).fill().map(() => console.log('test'));
This snippet will console.log test 4 times.
Answer: 09 December 2015
Personally, I found the accepted answer both concise (good) and terse (bad). Appreciate this statement might be subjective, so please read this answer and see if you agree or disagree
The example given in the question was something like Ruby's:
x.times do |i|
do_stuff(i)
end
Expressing this in JS using below would permit:
times(x)(doStuff(i));
Here is the code:
let times = (n) => {
return (f) => {
Array(n).fill().map((_, i) => f(i));
};
};
That's it!
Simple example usage:
let cheer = () => console.log('Hip hip hooray!');
times(3)(cheer);
//Hip hip hooray!
//Hip hip hooray!
//Hip hip hooray!
Alternatively, following the examples of the accepted answer:
let doStuff = (i) => console.log(i, ' hi'),
once = times(1),
twice = times(2),
thrice = times(3);
once(doStuff);
//0 ' hi'
twice(doStuff);
//0 ' hi'
//1 ' hi'
thrice(doStuff);
//0 ' hi'
//1 ' hi'
//2 ' hi'
Side note - Defining a range function
A similar / related question, that uses fundamentally very similar code constructs, might be is there a convenient Range function in (core) JavaScript, something similar to underscore's range function.
Create an array with n numbers, starting from x
Underscore
_.range(x, x + n)
ES2015
Couple of alternatives:
Array(n).fill().map((_, i) => x + i)
Array.from(Array(n), (_, i) => x + i)
Demo using n = 10, x = 1:
> Array(10).fill().map((_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
> Array.from(Array(10), (_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
In a quick test I ran, with each of the above running a million times each using our solution and doStuff function, the former approach (Array(n).fill()) proved slightly faster.
I am late to the party, but since this question turns up often in search results, I would just like to add a solution that I consider to be the best in terms of readability while not being long (which is ideal for any codebase IMO). It mutates, but I'd make that tradeoff for KISS principles.
let times = 5
while( times-- )
console.log(times)
// logs 4, 3, 2, 1, 0
Array(100).fill().map((_,i)=> console.log(i) );
This version satisifies the OP's requirement for immutability. Also consider using reduce instead of map depending on your use case.
This is also an option if you don't mind a little mutation in your prototype.
Number.prototype.times = function(f) {
return Array(this.valueOf()).fill().map((_,i)=>f(i));
};
Now we can do this
((3).times(i=>console.log(i)));
+1 to arcseldon for the .fill suggestion.
Not something I would teach (or ever use in my code), but here's a codegolf-worthy solution without mutating a variable, no need for ES6:
Array.apply(null, {length: 10}).forEach(function(_, i){
doStuff(i);
})
More of an interesting proof-of-concept thing than a useful answer, really.
If you're willing to use a library, there's also lodash _.times or underscore _.times:
_.times(x, i => {
return doStuff(i)
})
Note this returns an array of the results, so it's really more like this ruby:
x.times.map { |i|
doStuff(i)
}
Afaik, there is no mechanism in ES6 similar to Ruby's times method. But you can avoid mutation by using recursion:
let times = (i, cb, l = i) => {
if (i === 0) return;
cb(l - i);
times(i - 1, cb, l);
}
times(5, i => doStuff(i));
Demo: http://jsbin.com/koyecovano/1/edit?js,console
In the functional paradigm repeat is usually an infinite recursive function. To use it we need either lazy evaluation or continuation passing style.
Lazy evaluated function repetition
const repeat = f => x => [x, () => repeat(f) (f(x))];
const take = n => ([x, f]) => n === 0 ? x : take(n - 1) (f());
console.log(
take(8) (repeat(x => x * 2) (1)) // 256
);
I use a thunk (a function without arguments) to achieve lazy evaluation in Javascript.
Function repetition with continuation passing style
const repeat = f => x => [x, k => k(repeat(f) (f(x)))];
const take = n => ([x, k]) => n === 0 ? x : k(take(n - 1));
console.log(
take(8) (repeat(x => x * 2) (1)) // 256
);
CPS is a little scary at first. However, it always follows the same pattern: The last argument is the continuation (a function), which invokes its own body: k => k(...). Please note that CPS turns the application inside out, i.e. take(8) (repeat...) becomes k(take(8)) (...) where k is the partially applied repeat.
Conclusion
By separating the repetition (repeat) from the termination condition (take) we gain flexibility - separation of concerns up to its bitter end :D
Advantages of this solution
Simplest to read / use (imo)
Return value can be used as a sum, or just ignored
Plain es6 version, also link to TypeScript version of the code
Disadvantages
- Mutation. Being internal only I don't care, maybe some others will not either.
Examples and Code
times(5, 3) // 15 (3+3+3+3+3)
times(5, (i) => Math.pow(2,i) ) // 31 (1+2+4+8+16)
times(5, '<br/>') // <br/><br/><br/><br/><br/>
times(3, (i, count) => { // name[0], name[1], name[2]
let n = 'name[' + i + ']'
if (i < count-1)
n += ', '
return n
})
function times(count, callbackOrScalar) {
let type = typeof callbackOrScalar
let sum
if (type === 'number') sum = 0
else if (type === 'string') sum = ''
for (let j = 0; j < count; j++) {
if (type === 'function') {
const callback = callbackOrScalar
const result = callback(j, count)
if (typeof result === 'number' || typeof result === 'string')
sum = sum === undefined ? result : sum + result
}
else if (type === 'number' || type === 'string') {
const scalar = callbackOrScalar
sum = sum === undefined ? scalar : sum + scalar
}
}
return sum
}
TypeScipt version
https://codepen.io/whitneyland/pen/aVjaaE?editors=0011
The simplest way I can think of for creating list/array within range
Array.from(Array(max-min+1), (_, index) => index+min)
I have another alternative
[...Array(30).keys()]
addressing the functional aspect:
function times(n, f) {
var _f = function (f) {
var i;
for (i = 0; i < n; i++) {
f(i);
}
};
return typeof f === 'function' && _f(f) || _f;
}
times(6)(function (v) {
console.log('in parts: ' + v);
});
times(6, function (v) {
console.log('complete: ' + v);
});
Generators? Recursion? Why so much hatin' on mutatin'? ;-)
If it is acceptable as long as we "hide" it, then just accept the use of a unary operator and we can keep things simple:
Number.prototype.times = function(f) { let n=0 ; while(this.valueOf() > n) f(n++) }
Just like in ruby:
> (3).times(console.log)
0
1
2
I wrapped #Tieme s answer with a helper function.
In TypeScript:
export const mapN = <T = any[]>(count: number, fn: (...args: any[]) => T): T[] => [...Array(count)].map((_, i) => fn())
Now you can run:
const arr: string[] = mapN(3, () => 'something')
// returns ['something', 'something', 'something']
I made this:
function repeat(func, times) {
for (var i=0; i<times; i++) {
func(i);
}
}
Usage:
repeat(function(i) {
console.log("Hello, World! - "+i);
}, 5)
/*
Returns:
Hello, World! - 0
Hello, World! - 1
Hello, World! - 2
Hello, World! - 3
Hello, World! - 4
*/
The i variable returns the amount of times it has looped - useful if you need to preload an x amount of images.
I am just going to put this here. If you are looking for a compact function without using Arrays and you have no issue with mutability/immutability :
var g =x=>{/*your code goes here*/x-1>0?g(x-1):null};
For me, this is the easiest answer to understand for many levels of developers
const times = (n, callback) => {
while (n) {
callback();
n--;
}
}
times(10, ()=> console.log('hello'))
It seems to me that the most correct answer (which is debatable) to this question is buried in a comment by Sasha Kondrashov and is also the most concise, using just two characters: "no". There is no functional alternative to a for-loop as nice as the syntax that Ruby has. We might want there to be one, but there just isn't.
It is not explicitly stated in the question, but I would argue any solution to the problem of 'looping N times' should not allocate memory, at least not proportional to N. That criterium would rule out most of the answers that are 'native to javascript'.
Other answers show implementations like the one in Ruby, which is fine, except that the question explicitly asks for a native javascript solution. And there is already a very decent hand-rolled solution in the question, arguably one of the most readable of all.