Function 为什么不';Lua表达式中的t匿名函数?

Function 为什么不';Lua表达式中的t匿名函数?,function,lua,expression,Function,Lua,Expression,有人能解释一下为什么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 '('

有人能解释一下为什么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 5.3.3版权所有(C)1994-2016 Lua.org,临市局里约
>函数(x)返回x*x结束(2)
标准输入:1:预期接近'('
>平方=函数(x)返回x*x结束
>广场(2)
4.

哦,我明白了。对不起,需要圆括号

(function(x) return x*x end) (2)
我还是不明白为什么它设计成这样。

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

长话短说 我不知道为什么它是这样设计的,但我确实查阅了,看看它到底是如何工作的。下面是函数调用的条目:

functioncall::=prefixexp参数| prefixexp':'名称参数

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

前缀xp::=var | functioncall |'('exp')'

好的,我们可以调用另一个“functioncall”。“exp”只是一个普通表达式:

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

所以我们可以调用任何表达式,只要它在括号内。“functiondef”包含匿名函数:

functiondef::=函数funcbody

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

所以匿名函数是一个“exp”,而不是一个“prefixexp”,所以我们确实需要用括号括起来

什么是“var”

变量::=Name | prefixexp'['exp'].| prefixexp'.'Name

“var”是一个名称或一个索引值(通常是一个表)。请注意,索引值必须是一个“prefixexp”,这意味着在我们可以索引它们之前,字符串文本或表构造函数必须在括号中

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


最大的问题是:为什么“prefixexp”与“exp”的处理方式不同?我不知道。我怀疑这与保持函数调用和索引超出正常范围有关,但我不知道为什么这是必要的。

Lua的函数调用语法中内置了一些语法糖。可以通过以下三种方式调用函数:

  • 带括号的值列表
  • 表构造函数(函数将表作为单个参数)
  • 字符串文字
Lua希望它的语法有点规则,所以如果有一个东西可以用这些方法中的一种调用函数,那么用这些方法调用它应该是有意义的

考虑以下代码:

local value = function(args)
   --does some stuff
   end "I'm a literal" .. foo
如果我们允许像任何其他函数调用一样调用任意的、未解析的表达式,那么这意味着创建一个函数,使用字符串文本调用它,将该函数调用的结果与
foo
连接,并将其存储在
值中

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

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

  • Lua不能使用字符串文本进行函数调用。毕竟,您只保存了2个括号。甚至可能不允许使用表构造函数,尽管这些构造函数不那么难看,也不太容易混淆。让每个人在所有函数调用中都使用括号
  • Lua可以这样做,只有在lambda的情况下,才可以防止使用字符串文本的函数调用。这需要对语法进行大量的去规范化
  • 如果调用函数显然不是前面文本的预期结果,Lua可能会强制您在任何构造中插入括号
  • 现在,有人可能会说,
    table\u name[var\u name]“literal”
    对于正在发生的事情已经相当混乱了。但是,要防止这种情况发生,特别需要对语法进行去规范化。您必须添加所有这些特殊情况,例如
    name“literal”
    是函数调用,而
    name.name>是函数调用“literal”
    不是。因此选项2不适用

    使用字符串文本调用函数的能力并不局限于Lua,但您必须使用特定的文本语法来获得它。此外,能够键入
    要求“module_name”
    感觉是个好主意。由于这种调用被认为是一种重要的语法糖分,并得到了多种语言的支持,因此选项1不适用


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

    Lua的设计并没有考虑到IIFEs。你也需要在Javascript中使用括号,因为在Javascript中使用括号的频率更高。在Lua中,Javascript中IIFEs的大部分内容将改为
    do…end
    块。@Jasmijn:IIFEs可以重新绑定
    。使用
    {…}
    “它(稍微)违背了函数应该是第一类对象的想法”不,它不是。第一类对象的性质和语法表达式的性质彼此无关。实际上(我知道这将把这一论点推向了极限,不必太认真)我可以想象一种新的blogop类型的语言完全是第一类的,但是没有任何语法来构造它。如果你有一个包含blobop的变量,那么你可以对它做任何你想做的事情,包括赋值。但是它是无用的。IMHO,作为第一类对象是有用的(在精神上,如果不是在法律条文中)您需要支持语法。