在JavaScript中,
f = function(x) {
return x + 1;
}
(5)
看起来好像应该为后继函数赋值f
,但实际上赋值为6,因为括号后面跟着的lambda表达式被解析器解释为后缀表达式,特别是函数调用。幸运的是,这很容易解决:
f = function(x) {
return x + 1;
};
(5)
表现得像预期的那样。
如果Python允许lambda表达式中的块,则会出现类似的问题:
f = lambda(x):
return x + 1
(5)
但这次我们无法以同样的方式解决它,因为没有分号。在实践中,Python通过不允许多行lambda表达式来避免这个问题,但是我正在研究一种基于缩进语法的语言,我想要多行lambda和其他表达式,所以我试图弄清楚如何避免使用块解析为后缀表达式的开头。到目前为止,我想也许递归下降解析器的每个级别都应该有一个参数,即'我们已经在这个语句中吃了一个块,所以不要做后缀'。
是否存在遇到此问题的现有语言,如果是这样,他们如何解决?
答案 0 :(得分:1)
在Haskell中,假设解析器处于布局敏感模式,则每当您使用与前一个缩进相同的行开始时,都会有一个隐式分号。
更具体地,在遇到表示(布局敏感)块的开始的令牌之后,记住第一块项的第一令牌的缩进级别。每个缩进的行继续当前块项;每个缩进相同的行开始一个新的块项,缩进的第一行意味着块的关闭。如何处理您的上一个示例取决于f =
是否是某个块中的块项。如果是,则lambda表达式和(5)
之间将存在隐式分号,因为后者与前者缩进相同。如果不是,那么(5)
将被视为继续f =
所属的任何块项,使其成为lamda函数的参数。
细节比这更麻烦;看看Haskell 2010 report。
答案 1 :(得分:1)
Python 有分号。这完全有效(虽然丑陋且不推荐)Python代码:f = lambda(x): x + 1; (5)
。
但是,在其他标准Python语法中,多行lambda存在许多其他问题。它与Python处理缩进(实际上是一般的,实际上是空格)的方式完全不兼容 - 它没有,这与你想要的完全相反。你应该阅读关于多行lambda的众多python-ideas线程。它介于非常难以实现之间。
如果你想在lambdas中使用任意复杂的复合语句,即使你创建了所有的语句表达式,你也不能使用现有的多行表达式规则。您必须更改缩进处理(请参阅语言参考以了解它现在如何工作),以便表达式也可以包含块。如果不打破完美的Python代码就很难做到,并且肯定会导致许多Python程序员在某些方面会考虑更糟糕的语言:更难理解,实现更复杂,允许一些愚蠢的错误等等。
大多数语言根本无法解决这个问题。大多数候选者(Scala,Ruby,Lisps和这三者的变体)都有明确的块尾令牌。我知道有两种语言存在同样的问题,其中一种(Haskell)已被另一种答案提及。 Coffeescript也使用缩进而没有块尾令牌。它解析了您的示例correctly的音译。但是,我找不到任何关于它如何或为什么这样做的规范(我不会深入研究解析器源代码)。两者在语法和设计哲学上都与Python有很大不同,因此他们的解决方案对Python来说几乎没用(如果有的话)。