Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't enable tail call optimization in node v6.4.0

I wan't to play around with tail call optimization in node/es2015, but I keep getting RangeError: Maximum call stack size exceeded. So I tried a very simple test function:

  function countTo(n, acc) {
    if(n === 0) {
      return acc;
    }
    return countTo(n - 1, acc + n);
  }

  console.log(countTo(100000 , 0))

and it still fails. I've tried adding 'use strict'; inside the function body and at the top of the file. I've tried using --harmony and --harmony-tailcalls

The same function works as expected in racket:

#lang racket
(define count-to
  (lambda (n acc)
    (cond
      ((= n 0) acc)
      (else (count-to (- n 1) (+ acc n))))))
(count-to 100000000 0)
; ~> 5000000050000000

Edit:

As @MatthieuLemoine suggested. It works in v6.5.0+ with "use strict"; and either --harmony or --harmony-tailcalls

like image 965
sheepdog Avatar asked Sep 21 '16 13:09

sheepdog


2 Answers

Using node v6.5.0, the following works :

function countTo(n, acc) {
  'use strict';
  if(n === 0) {
    return acc;
  }
  return countTo(n - 1, acc + n);
}
console.log(countTo(100000 , 0));

Running with --harmony-tailcalls flag :

node --harmony-tailcalls tco.js
like image 77
MatthieuLemoine Avatar answered Sep 24 '22 21:09

MatthieuLemoine


You can use the tco module to emulate a tail call optimization even on old node. I'll add an example using your code to this answer in a minute.

Slightly changing your code, you can run even 10 million levels of recursion:

var tco = require('tco');
var countTo = tco(function (n, acc) {
  if (n === 0) {
    return [null, acc];
  }
  return [countTo, [n - 1, acc + n]];
});
console.log(countTo(10000000, 0));

You can use Sweet macros to make it look more like:

var countTo = tco(function (n, acc) {
  if (n === 0) {
    ret acc;
  }
  ret countTo(n - 1, acc + n);
});
console.log(countTo(10000000, 0));

Which is basically changing return to ret but currently my macros that I used before don't seem to work with the current version of Sweet.js - I have to investigate it when I have some time.

Disclaimer: I'm the author of that module.

like image 24
rsp Avatar answered Sep 23 '22 21:09

rsp