与Sweet.js的懒惰评估宏

时间:2015-03-16 08:54:13

标签: javascript lazy-evaluation 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);

它适用于单个expr。但是有些情况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();

我也不知道如何做到这一点。

2 个答案:

答案 0 :(得分:3)

$($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 ... })
    }
}

答案 1 :(得分:3)

由于您希望将其与大括号一起使用,因此您需要在宏中包含括号,例如@timdisney said

但是,要懒惰地评估像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