用JavaScript重构这个Lisp和Haskell风格的宏
考虑以下Lisp宏:用JavaScript重构这个Lisp和Haskell风格的宏,javascript,haskell,lisp,Javascript,Haskell,Lisp,考虑以下Lisp宏: (defmacro doif (x y) `(if ,x ,y)) 哈斯凯尔也是如此: doif x y=如果x那么(只有y)其他什么都没有 在JavaScript的“lisp-y”语言中有可能实现这种优雅吗?(单词“lisp-y”的用法来自JS语言的作者)我认为在非惰性语言中模拟惰性的通常方法是手动thunkify。我对Javascript不太了解,所以我将编写伪代码,希望您能在这个想法上绘制Javascript语法 function doif(x, y) {
(defmacro doif (x y) `(if ,x ,y))
哈斯凯尔也是如此:
doif x y=如果x那么(只有y)其他什么都没有
在JavaScript的“lisp-y”语言中有可能实现这种优雅吗?(单词“lisp-y”的用法来自JS语言的作者)我认为在非惰性语言中模拟惰性的通常方法是手动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)
是的,这是可能的。如果您只想对lisp-y代码进行一对一的映射,则可以使用以下方法:
x ? y : null // note that x and y are expressions, not values: they aren't eval'd
macro doif {
rule { ($x:expr) ($y:expr) } => { $x ? $y : null }
}
如果您不介意表达式的结果是falsy值(而不是显式的null
值),那么您可以使用:
如果要创建自己的doif
语法,则可以使用由提供的宏,如下所示:
x ? y : null // note that x and y are expressions, not values: they aren't eval'd
macro doif {
rule { ($x:expr) ($y:expr) } => { $x ? $y : null }
}
上述宏允许您编写如下代码:
doif (x < 100) (x + 1)
doif(x<100)(x+1)
上述代码将转换为:
x < 100 ? x + 1 : null
x<100?x+1:null
如果条件
x
为falsy,则使用这些运算符时,将不计算y
。您可以在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; });
函数my\u if(条件,然后是部分,否则是部分){
返回条件?然后_part():否则_part();
}
我的如果(foo
当然,您也可以创建一个闭包,通过延迟测试来封装整个操作
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
函数my\u if(条件,然后是部分,否则是部分){
返回函数(){
返回条件()?然后_部分():否则_部分();
}
}
var my_prog=my_if(function(){return foo
如果x
在javascript中是true
的话,你想执行y
吗?不,你不能得到这种优雅,因为JS既没有宏,也不是非严格的语言。请不要试图在JS中使用优雅这个词,它会导致抑郁;)@我不同意。JavaScript是一种非常优雅的语言。是的,它是不纯的,不像Haskell那样有代数数据类型或模式匹配。尽管如此,它仍然是一种非常强大的语言。JavaScript支持函数式、面向对象和过程式编程——三大编程风格。因此,您可以混合和匹配您喜欢的任何编程风格。此外,它还具有原型继承(我认为这是继承和代码重用的优雅解决方案)。此外,JS的学习曲线不像Haskell那样陡峭。顺便说一句,我也喜欢Haskell和FP。@AaditMShah:那只是我的经历:)。无论如何看看@6502:我同意。现在,您可以将Haskell、F#、Scala等编译为JS。JS运行时,像V8和各种Mozilla的猴子:)是令人惊奇的工具,但是他们必须考虑JS语言的语义,并且把他们的手绑在一起。看到然后就是DOM:)x?y:null
与lisp代码不同。x
和y
可以是任何表达式(而不仅仅是一些持有值的变量),这基本上意味着x和y都将以这种形式得到“评估”。检查x
@Ankur之前不计算y
所需的条件运算符只计算其第二个和第三个参数中的一个,因此在这方面与lisp代码类似。@Ankur我不同意。在这种情况下,x
和y
不是变量。它们是任何表达式的占位符。这就是我提供宏定义doif
的原因。如果您仔细查看,x
和y
属于expr
类型(任何表达式)。在这两种情况下,表达式y
仅在x
为真时才计算。@Ankur如果您不相信我,请查看演示:1)true?警报(“Hello World!”):null
(将警报“Hello World!”
):2)false?警报(“Hello World!”):null
(将不会警报“Hello World!”
):我认为不必调用y
。OP写了doif x y=if x then(只是y)else Nothing
。因此,即使y
是一个函数(很可能不是),它也只是被包装在一个值中。从来没有人叫过它。在我看来,正确的JavaScript转换是x?y:null
@AaditMShah我对这个问题的理解是,我们希望将某个条件的计算延迟到以后(在本例中,“以后”是“在我们知道某个条件是否为真之后”)。将计算放在函数中是延迟它的一种方法,而调用函数是停止延迟的一种方法。如果x
的计算结果为真实值,他只希望表达式返回y
。例如,考虑下面的LISP代码:<代码>(DOIF(。这应该转化为x<100?x+1:null
。把它翻译成doif(x<100,function(){returnx+1;})
是不必要的样板。在任何一种情况下,第二个表达式仅在条件为truthy时计算,这就是为什么您可以执行类似于条件的操作?警报(“你好,世界!”):null
。警报
功能仅在条件下调用