Sweet.js 的惰性求值宏
Lazy evaluation macro with Sweet.js
我刚进入 JavaScript 并注意到这种语言不直接支持惰性求值。本机代码变成了这样的样板地狱:
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;
});
但是我发现Sweet.js并且相信它可以使代码像这样简单:
var foo = lazy (3 + 3);
var goo = lazy {
var a = 3 + 3;
return a;
};
所以我测试了 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);
它使用单个表达式。但是有些情况下 lazy
像这样接受一个 expr 块:
var goo = lazy {
var a = 3 + 3;
return a;
};
所以我把上面的代码整理成这样:
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;
};
而且由于某种原因它不起作用。我相信第一个模式 $($expr) (;) ...
不应该与 (3 + 3)
匹配,但显然它正在匹配。
我为此工作了一个小时,最后放弃了。如何让这两种模式同时工作?
如果实在不行,我想换个方式求一个expr:
lar foo = 3 + 3;
var foo_content = foo();
而且我也不知道该怎么做。
$($expr) (;) ...
表示重复匹配由;
分隔的单个标记。你可能想要这个:
macro lazy {
// match single expression in parens
rule { ( $e:expr ) } => {
lazy_f(function() { return $e })
}
// match all of the tokens inside a curly
rule { { $expr ... } } => {
lazy_f(function() { $expr ... })
}
}
因为要用花括号,所以需要在宏中包含括号,如.
但是,要惰性计算像 var a = lazy this.x * this.y
这样的表达式,您需要将表达式正确绑定到 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;
})
}
}
这应该适用于任何有效表达式。
例子
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
我刚进入 JavaScript 并注意到这种语言不直接支持惰性求值。本机代码变成了这样的样板地狱:
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;
});
但是我发现Sweet.js并且相信它可以使代码像这样简单:
var foo = lazy (3 + 3);
var goo = lazy {
var a = 3 + 3;
return a;
};
所以我测试了 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);
它使用单个表达式。但是有些情况下 lazy
像这样接受一个 expr 块:
var goo = lazy {
var a = 3 + 3;
return a;
};
所以我把上面的代码整理成这样:
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;
};
而且由于某种原因它不起作用。我相信第一个模式 $($expr) (;) ...
不应该与 (3 + 3)
匹配,但显然它正在匹配。
我为此工作了一个小时,最后放弃了。如何让这两种模式同时工作?
如果实在不行,我想换个方式求一个expr:
lar foo = 3 + 3;
var foo_content = foo();
而且我也不知道该怎么做。
$($expr) (;) ...
表示重复匹配由;
分隔的单个标记。你可能想要这个:
macro lazy {
// match single expression in parens
rule { ( $e:expr ) } => {
lazy_f(function() { return $e })
}
// match all of the tokens inside a curly
rule { { $expr ... } } => {
lazy_f(function() { $expr ... })
}
}
因为要用花括号,所以需要在宏中包含括号,如
但是,要惰性计算像 var a = lazy this.x * this.y
这样的表达式,您需要将表达式正确绑定到 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;
})
}
}
这应该适用于任何有效表达式。
例子
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