为什么 Lua 表达式中没有匿名函数?


有人能向我解释为什么Lua中的匿名函数构造不是一个成熟的表达式吗?对我来说,这似乎是一个奇怪的现象:它(稍微)违背了函数应该是第一类对象的想法,而且(不经常但偶尔)对一种经过深思熟虑和优雅的语言来说是一种不便。

例如,使用命令行Lua,使用变通方法

Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> function(x) return x*x end (2)
stdin:1: <name> expected near '('
> square = function(x) return x*x end
> square(2)
4

Lua的函数调用语法中内置了一些语法糖

  • 带括号的值列表
  • 表构造函数(函数将把表作为一个参数)
  • 字符串文字

Lua希望在语法上有一定的规则性。因此,如果有一个东西可以用其中一种方式作为函数调用,那么用其中任何一种方式调用它都是有意义的。

考虑以下代码:

local value = function(args)
--does some stuff
end "I'm a literal" .. foo

如果我们允许像任何其他函数调用一样调用任意的未加括号的表达式,那么这意味着创建一个函数,用字符串文字调用它,将该函数调用的结果与foo连接,并将其存储在value中。

但是。。。我们真的想要工作吗?也就是说,我们希望人们能够编写它并使其成为有效的Lua代码吗?

如果这样的代码被认为是难看或令人困惑的,那么有几个选项。

  1. Lua不能使用字符串文本进行函数调用。毕竟,你只保存了两个括号。也许甚至不允许使用表构造函数,尽管它们不那么难看,也不那么令人困惑。让每个人在所有函数调用中都使用括号
  2. Lua可以做到,只有在Lambda的情况下,才可以阻止使用字符串文字的函数调用。这将需要对语法进行实质性的去规则化
  3. Lua可能会迫使您在调用函数不是前面文本的明显预期结果的任何构造中加括号

现在,有人可能会说table_name[var_name] "literal"已经相当令人困惑了。但同样,要防止这种情况发生,需要对语法进行去规则化。您必须添加所有这些特殊情况,比如name "literal"是函数调用,而name.name "literal"不是。因此,选项2不可用。

用字符串文字调用函数的能力几乎不局限于Lua。JavaScript可以做到这一点,但你必须使用特定的文字语法才能做到。此外,能够键入require "module_name"感觉是个好主意。由于这样的调用被认为是一种重要的语法糖,并且得到了几种语言的支持,因此选项#1已经过时了。

所以你唯一的选择是#3:让人们把他们想调用的表达式用括号括起来。

哦,我明白了。。抱歉,需要圆括号。

(function(x) return x*x end) (2)

我仍然不明白为什么它是这样设计的。

简短回答

若要调用函数,函数表达式必须是名称、索引值、另一个函数调用或括号内的表达式。

答案很长

我不知道为什么它是这样设计的,但我确实查了语法,看看它是如何工作的。以下是函数调用的条目:

函数调用::=prefixexp args|prefixexp':'名称args

"args";只是括号中的参数列表。相关部分是";prefixexp";。

prefixexp::=var|functioncall|'('exp')'

好的,所以我们可以调用另一个"函数调用"exp";只是一个正常的表达式:

exp::=nil|false|true|Numeral|LiteralString|'…'|functiondef|prefixexp|tableconstructor|exp-binop-exp|unop-exp-

所以我们可以调用任何表达式,只要它在括号内"functiondef";涵盖匿名函数:

functiondef::=函数函数体

funcbody::='('[pallist]')'块结束

所以匿名函数是一个";exp";,但不是";prefixexp";,所以我们确实需要在它周围加括号。

什么是";var";?

var::=Name|prefixexp'['exp']'|prefixxp'.'名称

"var";是名称或索引值(通常是表)。注意,被索引的值必须是"0";prefixexp";,这意味着字符串文字或表构造函数必须在括号中,然后才能对其进行索引。

总之:被调用的函数必须是名称、索引值、函数调用或括号内的其他表达式。

最大的问题是:为什么;prefixexp";与";exp";?我不知道。我怀疑这与保持函数调用和索引在正常运算符优先级之外有关,但我不知道为什么这是必要的。

最新更新