【问题标题】:Lazy evaluation macro with Sweet.jsSweet.js 的惰性求值宏
【发布时间】:2015-03-16 08:54:12
【问题描述】:

我刚接触 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();

我也不知道该怎么做。

【问题讨论】:

    标签: javascript lazy-evaluation sweet.js


    【解决方案1】:

    由于您想将其与大括号一起使用,因此您需要在宏中包含括号,例如@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
    

    【讨论】:

    • 感谢您提供完整的解决方案! :))
    • @RyoichiroOka 请确保包含 @SeanVieira 的最新编辑。我忘记在我发布的代码中将result 设置为函数的结果。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2015-03-26
      • 1970-01-01
      • 2012-08-31
      • 2011-02-23
      • 2013-12-30
      • 2020-05-19
      • 2016-10-11
      • 2010-09-29
      • 1970-01-01
      相关资源
      最近更新 更多