LSR 004 - 匿名函数表达式

基本信息

  • LSR 编号 004
  • 标题 匿名函数表达式
  • 作者 sugared functor, CGrakeski
  • 状态 草案
  • 类型 标准规范
  • 创建日期 2025年8月13日
  • Lamina 版本 未决议

摘要

匿名函数表达式,又称lambda表达式,在部分语言也叫闭包,在下文讨论中简称为lambda

lambda是一种没有名称的函数,它们通常用在需要临时使用某些函数,且使用完毕后即可被丢弃(也即只用一次)的场景。

为了使得Lamina语言紧跟现代化语言的行列,特设立本草案。

技术规范

注:语法参考于尾随系lambda语言,本草案作者也建议使用该风格的lambda,具体原因请见下文

lamdba的语法如下:

{ arg1,arg2 -> code() }

使用antlr文法描述如下:

lambda : '{' stmt* '}'
       | '{' name (',' name)* '->' stmt* };

当lambda不需要参数时,允许lambda不声明参数列表:

{ code(); };

lambda也可以复制给变量,调用被赋值的变量与调用正常函数一致:

var f = {};
f();

也可以调用字面量

{}();

调用表达式使用antlr写作:

expr : invoke | ... ;
invoke : expr '(' expr? (',' expr)* ')';

该文法是左递归文法

大部分现代化语言将自动返回lambda的最后一个表达式的值,故本草案如此规定。

var value = { 1 ; 2 ; }();
//value为2

尾随匿名函数

尾随匿名函数是一种语法糖。当我们传给函数lamdba时,我们会这样写:

func foo(f) {
    f();
}
foo({ print("okay"); });

调用foo函数时包裹参数的括号是可选的,如尾随风格的匿名函数直接去掉括号:

foo { print("okay"); };

对于多参函数则采用如下方法:

//下面两个调用相同
foo(1,{ print("okay"); });
foo(1) { print("okay"); };

尾随匿名函数的antlr定义如下

expr : invoke | lambda | ... ;
invoke : expr '(' expr? (',' expr)* ')'
       | expr ('(' expr? (',' expr)* ')')? lambda ;

该文法是左递归文法

多尾随匿名函数

目前大部分尾随风格系的lambda语言都不支持多尾随匿名函数,故本草案作者不支持也不反对该部分提议

尾随匿名函数参见上文,若函数具有多个函数参数,如:

func foo(f1,f2) {
    f1();
    f2();
}

则写作多尾随调用可如此:

foo { print("1"); } { print("2"); };