在JavaScript中重构这个Lisp和Haskell样式宏

时间:2013-10-14 09:19:20

标签: javascript haskell lisp

考虑一下这个Lisp宏:

(defmacro doif (x y) `(if ,x ,y))

在Haskell中也一样:

doif x y = if x then (Just y) else Nothing

是否有可能在JavaScript的“lisp-y”语言中实现这种优雅? (使用“lisp-y”一词来自JS语言的作者)

3 个答案:

答案 0 :(得分:3)

是的,有可能。如果您只想一个lisp-y代码的一对一映射,那么您可以使用conditional operator,如下所示:

x ? y : null // note that x and y are expressions, not values: they aren't eval'd

如果您不介意表达式的结果是假值(而不是明确的null值),那么您可以改为使用guard operator

x && y // reminder: x and y are expressions - they aren't evaluated until needed

如果您想创建自己的doif语法,则可以使用sweet.js提供的卫生宏,如下所示:

macro doif {
    rule { ($x:expr) ($y:expr) } => { $x ? $y : null }
}

上面的宏允许你编写如下代码:

doif (x < 100) (x + 1)

以上代码转换为:

x < 100 ? x + 1 : null

如果条件x是假的,则使用其中任何一个运算符时,不会评估y

答案 1 :(得分:1)

我认为用非懒惰语言模仿懒惰的通常方法是手动thunkify。我不太了解Javascript,所以我打算编写伪代码,希望你可以在这个想法上绘制Javascript语法。

function doif(x, y) {
    if(x) { return y(); }
    else  { return undefined; }
}

示例电话:

function expensive() {
    // do a lot of work here
}
doif(false, expensive); // runs very fast
doif(true , expensive); // runs very slow
doif(true , expensive); // runs very slow (unlike Haskell, but I think like Lisp)

答案 2 :(得分:1)

您可以在Javascript中实现宏,因为编译器是运行时的一部分(您可以eval一个字符串并获取代码)。但是为了接近Lisp,您需要实现自己的完整语言,因为eval只能生成完整的函数,而不能生成表达式。

如果您只是考虑延迟评估,可以通过将代码包装在闭包中来轻松完成:

function my_if(condition, then_part, else_part) {
    return condition ? then_part() : else_part();
}

my_if(foo < bar,
      function(){ return bar -= foo; },
      function(){ return foo -= bar; });

你当然也可以通过延迟测试来创建一个封装整个操作的闭包......

function my_if(condition, then_part, else_part) {
    return function() {
        return condition() ? then_part() : else_part();
    }
}

var my_prog = my_if(function(){ return foo < bar; },
                    function(){ return bar -= foo; },
                    function(){ return foo -= bar; });

my_prog(); // executes the code