I just got in JavaScript and noticed that lazy evaluation is not directly supported in this language. Natively the code turns into the hell of boiler plate like this:
function lazy(f) {
var v = undefined;
return function() {
if (v == undefined)
v = f();
return v;
}
}
// 10 times larger than actual operation
var foo = lazy(function() {
return 3 + 3;
});
But I found Sweet.js and believe that it can make the code simple like this:
var foo = lazy (3 + 3);
var goo = lazy {
var a = 3 + 3;
return a;
};
So I tested out Edit Sweet.js:
function lazy_f(f) {
var v = undefined;
return function() {
if (v == undefined)
v = f();
return v;
}
}
macro lazy {
rules { $expr } => {
lazy_f(function() { return $expr; })
}
}
var foo = lazy (3 + 3);
It worked with a single expr. But there are cases that lazy
takes in a block of expr like this:
var goo = lazy {
var a = 3 + 3;
return a;
};
So I arranged the above code like this:
function lazy_f(f) {
var v = undefined;
return function() {
if (v == undefined)
v = f();
return v;
}
}
macro lazy {
rule { $($expr) (;) ... } => { //
lazy_f(function() $expr ...); //
} //
rules { $expr } => {
lazy_f(function() { return $expr; })
}
}
var foo = lazy (3 + 3);
var goo = lazy {
var a = 3 + 3;
return a;
};
And it doesn't work for some reason. I believe the first pattern $($expr) (;) ...
shouldn't match with (3 + 3)
, but apparently it's doing.
I worked on this for an hour and finally gave up. How do you make the two patterns working at the same time?
If it's not possible to do so, I would like to take another way for a single expr:
lar foo = 3 + 3;
var foo_content = foo();
And I don't know how to do this as well.
Since you want to use it with curly brackets, you need to include the brackets in the macro, like @timdisney said.
However, to lazily evaluate an expression like var a = lazy this.x * this.y
, you need to properly bind the expression to the current value of this
.
function lazyEvaluate(thisObject, functionToEvaluate) {
var result, hasResult = false;
return function () {
if (hasResult) {
return result;
} else {
hasResult = true;
return result = functionToEvaluate.call(thisObject);
};
};
}
let lazy = macro {
rule {
{
$statements ...
}
} => {
lazyEvaluate(this, function () {
$statements ...
})
}
rule { $expression:expr } => {
lazyEvaluate(this, function () {
return $expression;
})
}
}
This should work for any valid expression.
var a = 5, b = 2, c = lazy a * b, d = lazy {
console.log(c());
return c() * a;
};
a = 10;
console.log(c()); // 20
a = 5;
console.log(d()); // 100