krzkaczor / babel-plugin-tailcall-optimization Goto Github PK
View Code? Open in Web Editor NEWTail call optimization for JavaScript!
License: MIT License
Tail call optimization for JavaScript!
License: MIT License
as far as I know (which is very limited I guess ๐ ) the previous stack should be deleted but , how the conversion which you mentioned in the docs is helping with the TCO ?
What I understood from the samples is that it is converting the recursion into an iterating while loop ri8 !
It is overcoming the stack error but Is it TCO ?
Please correct me if I am wrong !...
Thanks
Krzysztof, can you shed some light why plugins' optimization is a thing? I'm refering to introduced optimizations.
If you try to compile something with this basic setup, the plugin fails:
.babelrc:
{
"presets": ["es2015"],
"plugins": ["tailcall-optimization"]
}
test.js:
export default function(foo) { console.log(foo); }
And you will receive an error about name not being found on the id
of path.node
.
next
branch directly from git repo via NPM, because either the build step or it is me who is missing a step here. (I don't consider this a problem that generated code is missing from the git repo, just a fact.)Questions:
Hi! This is a nice plugin. I once created a TCO library https://github.com/dai-shi/continuation.js.
It is so slow that I don't feel like fitting with Babel plugins, but it supports mutual recursions. It's faster than Traceur when I tested a simple example a while back, though.
The question I want to raise here is if someone is interested in mutual recursions.
As a start, I wonder if anyone can look into this.
http://glat.info/js.metaret/
Thanks.
When closure is detected what about pre-processing using a combination of copying params/var decelerations to a state object (when those refs are used via closure) in the function and update all refs to point to this state.
And converting all declared functions in the closure to automatically invoked curried functions that apply the state ref via closure.
I believe this would fix any issues related to function scoping rules including referencing of primitive datatypes since the automatically invoked curried functions would be applied with object refs and would keep that reference even if the parent scope re-assigned a new object ref to the state object variable
Basically a statement like this
function someMethod(min, b) {
const val = b.find(s => s.min < min)
...
return someCondition ? someMethod(val.min, someStatementOf(val)) : val.min
}
would convert to something like this
function someMethod(min, b) {
var _b, _min
...
while(true){
// at start of each iteration assign _state to a new object with updated values
// this allows for automatically invoked curried functions that were applied in a previous iteration to
// keep ref to that object while the next iteration scope can work cleanly on the new object with
// updated values
const _state = {
min,
}
const val = b.find((state => s => s.min < state['min'])(_state))
if(someCondition){
_min = val.min
_b = someStatementOf(val)
b = _b
min = _min
continue;
}
else {
return val.min
}
}
}
OS: Linux (Arch)
Node.js: v7.4.0
babel-cli: 6.23.0 (babel-core 6.23.1)
babel-plugin-tailcall-optimization: 1.0.11
The if/else case is correctly handled e.g.:
function factorial (n) {
return factorialAccum(1, n)
}
function factorialAccum (accum, n) {
if (n === 1) {
return accum
} else {
return factorialAccum(accum * n, n - 1)
}
}
console.log(factorial(5))
"use strict";
function factorial(n) {
return factorialAccum(1, n);
}
function factorialAccum(accum, n) {
var _repeat = true;
var _accum, _n;
while (_repeat) {
_repeat = false;
if (n === 1) {
return accum;
} else {
_accum = accum * n;
_n = n - 1;
accum = _accum;
n = _n;
_repeat = true;
continue;
}
}
}
console.log(factorial(5));
But the equivalent code written with the ternary operator isn't transformed:
function factorial (n) {
return factorialAccum(1, n)
}
function factorialAccum (accum, n) {
return n === 1 ? accum : factorialAccum(accum * n, n - 1)
}
console.log(factorial(5))
"use strict";
function factorial(n) {
return factorialAccum(1, n);
}
function factorialAccum(accum, n) {
return n === 1 ? accum : factorialAccum(accum * n, n - 1);
}
console.log(factorial(5));
Great plugin. Thanks for writing. Are conditionals supposed to be supported?
This sample input
const countJumps = (list, index, step) => {
const value = list.get(index);
if (value === undefined) return step;
return countJumps(list.set(index, value + 1), index + value, step + 1);
};
const countJumpsTernary = (list, index, step) => {
const value = list.get(index);
return value === undefined
? step
: countJumps(list.set(index, value + 1), index + value, step + 1);
};
Produces this output
const countJumps = (list, index, step) => {
var _repeat = true;
var _list, _index, _step;
while (_repeat) {
_repeat = false;
const value = list.get(index);
if (value === undefined) return step;
_list = list.set(index, value + 1);
_index = index + value;
_step = step + 1;
list = _list;
index = _index;
step = _step;
_repeat = true;
continue;
}
};
const countJumpsTernary = (list, index, step) => {
const value = list.get(index);
return value === undefined ? step : countJumps(list.set(index, value + 1), index + value, step + 1);
};
Is this the expected behavior?
I'm using a fresh install of babel with "tailcall-optimization"
as my only plugin.
Shouldn't some of these dependencies be in fact devDependencies?
"dependencies": {
"babel-cli": "^6.11.0",
"babel-core": "^6.13.0",
"babel-preset-es2015": "^6.13.0",
"babel-traverse": "^6.13.0",
"babylon": "^6.8.0"
},
Or else babel-plugin-tailcall-optimization
ends up as a heavy dependency.
const counter = (n, acc = 0) => { return n === 0 ? acc : counter(n - 1, acc + 1) };
transpiles to:
const counter = (n, acc = 0) => {
var _repeat = true;
var _n, _acc;
while (_repeat) {
_repeat = false;
if (n === 0) {
return acc;
} else {
_n = n - 1;
_acc = acc + 1;
n = _n;
acc = _acc;
_repeat = true;
continue;
}
}
};
but
const counter = (n, acc = 0) => n === 0 ? acc : counter(n - 1, acc + 1);
does not get changed
Run-time error:
TypeError: _bpp is not a function
See _bpp in the generated code, below.
Input:
function toScreen(bpp, [next, ...rest], offset, acc) {
if (!next) {
return acc;
}
var [start, end] = next,
len = (end - start + 1) / bpp;
return toScreen(bpp, rest, len + offset, acc.concat([[offset, len + offset]]));
}
output:
"use strict";
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
function toScreen(bpp, _ref, offset, acc) {
var _ref2 = _toArray(_ref);
var next = _ref2[0];
var rest = _ref2.slice(1);
var _repeat = true;
var _bpp, _temp, _offset, _acc;
while (_repeat) {
var _temp2, _temp3;
_repeat = false;
if (!next) {
return acc;
}
var _next = next;
var _next2 = _slicedToArray(_next, 2);
var start = _next2[0];
var end = _next2[1];
var len = (end - start + 1) / bpp;_bpp = bpp
_temp = rest
_offset = len + offset
_acc = acc.concat([[offset, len + offset]])
bpp = _bpp
(_temp2 = _temp, _temp3 = _toArray(_temp2), next = _temp3[0], rest = _temp3.slice(1), _temp2)
offset = _offset
acc = _acc
_repeat = true;
continue;
}
}
Lack of semicolons results in this parsing as a function call.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.