Skip to content

Instantly share code, notes, and snippets.

@J-Chaniotis
Created August 11, 2014 01:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save J-Chaniotis/4d4f516de7bd0acd38a8 to your computer and use it in GitHub Desktop.
Save J-Chaniotis/4d4f516de7bd0acd38a8 to your computer and use it in GitHub Desktop.
/*
Sweet.js version: 0.7.0
node.js 0.10.30
more info about tco function at: https://gist.github.com/Gozala/1697037
*/
var tco = function (f) {
var value, active = false, accumulated = [];
return function accumulator() {
accumulated.push(arguments);
if (!active) {
active = true;
while (accumulated.length) {
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
};
let tailFunction = macro {
/*
function inside object
var o = {
example: tailFunction () {...}
}
*/
case infix {$name :|tailFunction ($args (,) ...) { $body ... }} => {
return #{$name: tco(function ($args (,) ...){
$body ...
})}
}
/*
function expression
var example = tailFunction () {...}
*/
case {_ ($args (,) ...) { $body ... }} => {
return #{tco(function ($args (,) ...){
$body ...
})}
}
/*
function declaration and named function expression
tailFunction example () {...}
var example = tailFunction example () {...}
*/
case {_ $name ($args (,) ...) { $body ... }} => {
return #{function $name(){
if(! $name.__tco) {
$name.__tco = tco(function ($args (,) ...) {
$body...
});
}
return $name.__tco.apply($name.__tco, arguments);
}}
}
}
/*
Recognized Syntax
insipred from: http://us6.campaign-archive2.com/?u=2cc20705b76fa66ab84a6634f&id=9bd21a4dce
*/
// Function declaration
tailFunction isEvenNaiveS1 (num) {
if (num === 0) {
return true;
}
if (num === 1) {
return false;
}
return isEvenNaiveS1(Math.abs(num) - 2);
}
console.log(isEvenNaiveS1(99999));
// Function expression
var isEvenNaiveS2 = tailFunction (num) {
if (num === 0) {
return true;
}
if (num === 1) {
return false;
}
return isEvenNaiveS2(Math.abs(num) - 2);
}
console.log(isEvenNaiveS2(99999));
// Inside object
var o = {
isEvenNaiveS3: tailFunction (num) {
if (num === 0) {
return true;
}
if (num === 1) {
return false;
}
return o.isEvenNaiveS3(Math.abs(num) - 2);
}
};
console.log(o.isEvenNaiveS3(99999));
// Named function expression
var isEvenNaiveS4 = tailFunction isEvenNaiveS4(num) {
if (num === 0) {
return true;
}
if (num === 1) {
return false;
}
return isEvenNaiveS4(Math.abs(num) - 2);
}
console.log(isEvenNaiveS4(99999));
@J-Chaniotis
Copy link
Author

This is my first attempt to play around with sweet.js, any suggestions/feedback would be appreciated

@nmn
Copy link

nmn commented Aug 15, 2014

I have been giving this problem some thought. Not sure if my solution is better but I think I have a way where the tco function would not be needed.

any tailcall optimizable function can simply be wrapped in a while loop, in order to simulate a jump statement.

tailFunction isEvenNaiveS4(num) {
    if (num === 0) {
        return true;
    }
    if (num === 1) {
        return false;
    }
    return isEvenNaiveS4(Math.abs(num) - 2);
} 

=>

function optimised(a){
    var num = a;
    var run = true;
    while(run){
        run = false;

        //Put almost all the function body here
        if (num === 0) {
            return true;
        }
        if (num === 1) {
            return false;
        }

        //return isEvenNaiveS4(Math.abs(num) - 2);
        // turns to:
        num = Math.abs(num) - 2;
        // would require destructuring logic
        run = true;
        continue;

        // Any other logic after the tail call can go here in case the tail call is wrapped in a conditional
    }
}

I don't get how to work with sweetjs yet, and I'm not even sure if this tranform is possible. But I think this is a simpler solution and possibly have better performance. I know I've missed the edge case of the arguments array, but that shouldn't be too hard to add;

@trxcllnt
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment