考虑一下这个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语言的作者)
答案 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