Syntax pythonnesque块和后缀表达式

Syntax pythonnesque块和后缀表达式,syntax,indentation,language-design,Syntax,Indentation,Language Design,在JavaScript中 f = function(x) { return x + 1; } (5) 乍一看似乎应该为后继函数赋值,但实际上赋值为6,因为后面跟着括号的lambda表达式被解析器解释为后缀表达式,特别是函数调用。幸运的是,这很容易解决: f = function(x) { return x + 1; }; (5) 表现如预期 如果Python允许在lambda表达式中使用块,则会出现类似的问题: f = lambda(x): return x + 1

在JavaScript中

f = function(x) {
    return x + 1;
}
(5)
乍一看似乎应该为后继函数赋值,但实际上赋值为6,因为后面跟着括号的lambda表达式被解析器解释为后缀表达式,特别是函数调用。幸运的是,这很容易解决:

f = function(x) {
    return x + 1;
};
(5)
表现如预期

如果Python允许在lambda表达式中使用块,则会出现类似的问题:

f = lambda(x):
    return x + 1
(5)
但是这一次我们不能用同样的方法解决它,因为没有分号。实际上,Python通过不允许多行lambda表达式来避免这个问题,但我正在开发一种基于缩进语法的语言,在这种语言中,我确实需要多行lambda和其他表达式,因此我试图找出如何避免将块解析作为后缀表达式的开始。到目前为止,我认为递归下降解析器的每一级都应该有一个参数,类似于“我们已经在这个语句中吃了一个块,所以不要做后缀”


是否有任何现有语言会遇到此问题,如果是,它们如何解决此问题?

在Haskell中,假设解析器处于布局敏感模式,每当您以与前一行相同的缩进开始一行时,都会有一个隐式分号

更具体地说,在遇到表示(布局敏感)块开始的标记后,将记住第一块项的第一标记的缩进级别。缩进更多的每一行继续当前块项;缩进相同的每一行开始一个新的块项,缩进较少的第一行表示块的结束

如何处理上一个示例取决于
f=
是否是某个块中的块项。如果是,则lambda表达式和
(5)
之间将有一个隐式分号,因为后者的缩进与前者相同。如果不是,则
(5)
将被视为继续
f=
所属的任何块项,使其成为lamda函数的参数

细节比这更混乱;请看。

Python有分号。这是非常有效的Python代码(尽管很难看,也不推荐使用):
f=lambda(x):x+1;(5) 

不过,在其他标准Python语法中,多行lambda还有许多其他问题。它与Python在表达式中处理缩进(实际上是空白)的方式完全不兼容——事实并非如此,这与您想要的完全相反。您应该阅读大量关于多行lambda的python思想线程。这是介于非常困难和不可能之间的一种情况

如果希望在lambdas中使用任意复杂的复合语句,则即使生成了所有语句表达式,也不能将现有规则用于多行表达式。您必须更改缩进处理(请参阅language reference,了解其目前的工作方式),以便表达式也可以包含块。在不破坏完美的Python代码的情况下,这是很难做到的,并且肯定会导致许多Python程序员会在几个方面考虑更差:更难理解,更复杂的实现,允许一些愚蠢的错误等等。
大多数语言根本不能解决这个问题。大多数候选者(Scala、Ruby、Lisp和这三种语言的变体)都有显式的块结束标记。我知道有两种语言有相同的问题,其中一种(Haskell)被另一个答案提到。Coffeescript还使用不带块尾标记的缩进。它解析您的示例的音译。然而,我找不到任何关于它是如何或为什么这样做的规范(我不会深入研究解析器源代码)。两者在语法和设计理念上都与Python有很大的不同,因此它们的解决方案对Python几乎没有用处(如果有的话)。

没错,我已经实现了很多;但仍然有我给出的示例,缩进与前一行不同。最后一个示例可能是Haskell样式解析方案下的解析错误。假设
f=…
是一个块项目,那么
(5)
将作为该块中的下一个块项目。如果
f=…
不是块项,那么方案当然会将
(5)
视为lambda函数的参数。