Files
endorphin-tabularium-docs/content/docs/language-design/07-questions.md
T
codex-bot ef1ba88161
Verify and deploy Tabularium / verify-and-deploy (push) Waiting to run
Add language design question collection with discussion decisions and provenance
2026-10-28 14:02:12 +08:00

183 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 07 · 函数与调用
0/22 项已确认。当前推进 07-01;本分类尚未完成选择。
本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。
## 07-01 函数作为值【进行中】
- [ ] 待讨论
明确能否赋值、存入数据、作为参数和返回结果,以及受限情形。
## 07-02 函数定义与创建
- [ ] 待讨论
明确具名函数、匿名函数是否支持;定义何时创建函数、何时可见,重复定义怎样处理。
## 07-03 可调用目标
- [ ] 待讨论
明确哪些值可以调用,调用非函数如何失败;方法、可调用对象若存在,明确接入边界。依赖:**对象与类型模型**。
## 07-04 调用的求值策略与顺序
- [ ] 待讨论
明确实参是立即求值还是延迟求值,调用目标与实参的求值顺序,以及求值中断后的行为。
## 07-05 参数传递与修改
- [ ] 待讨论
明确形参赋值、修改实参所指数据分别有什么效果;是否支持引用、借用或其他传递方式。依赖:**变量与内存模型、类型系统**。
## 07-06 位置参数
- [ ] 待讨论
明确按什么顺序绑定,是否支持仅限位置的参数;数量不足或过多怎样处理。
## 07-07 命名参数
- [ ] 待讨论
明确是否支持、参数名是否属于公开接口、与位置参数如何混用,以及未知名称与重复绑定的处理。
## 07-08 默认参数
- [ ] 待讨论
明确求值时机、可访问的名字、默认值之间的依赖、可变默认值的共享行为,以及省略与显式传空值的区别。
## 07-09 可变参数与展开
- [ ] 待讨论
明确是否支持剩余位置参数、剩余命名参数及调用展开;规定收集形式、顺序、重复名称与非法展开。
## 07-10 绑定失败的统一规则
- [ ] 待讨论
明确绑定失败何时发现、是否执行函数体、此前哪些表达式可能已执行,以及错误如何报告。依赖:**错误处理**。
## 07-11 返回与无结果
- [ ] 待讨论
明确显式返回、执行到末尾、无结果与空值、多结果及接收数量不符的行为。
## 07-12 递归与名字绑定
- [ ] 待讨论
明确自递归、相互递归、局部递归函数是否支持,以及重绑定函数名后递归调用指向什么。依赖:**作用域与模块**。
## 07-13 尾调用与调用深度
- [ ] 待讨论
明确是否保证尾调用、哪些位置算尾位置,以及调用深度耗尽怎样失败。依赖:**控制流与运行时**。
## 07-14 闭包的名字解析
- [ ] 待讨论
明确是否支持访问外层局部名字,采用词法作用域还是其他规则,以及遮蔽和未绑定名字的行为。依赖:**作用域**。
## 07-15 闭包捕获与共享状态
- [ ] 待讨论
明确捕获值还是变量、自动还是显式捕获,以及多个闭包、循环变量与外部修改之间的关系。依赖:**变量与内存模型**。
## 07-16 闭包逃逸与生命周期
- [ ] 待讨论
明确闭包能否比创建它的调用活得更久,捕获的资源如何保持有效,不能逃逸时如何拒绝。依赖:**资源管理与类型系统**。
## 07-17 函数的调用接口
- [ ] 待讨论
明确函数签名包含哪些信息、怎样检查兼容性;重载或泛型若存在,明确调用选择的接口。依赖:**类型系统**。
## 07-18 函数身份与比较
- [ ] 待讨论
明确函数是否可比较、复制后是否保持身份、重复创建的闭包有什么关系,以及能否作为键。依赖:**值与相等性模型**。
## 07-19 非普通控制流的调用边界
- [ ] 待讨论
明确异常、异步、生成器等若被采用,对调用与返回产生什么影响;只规定函数侧接口。依赖:**错误处理、并发与控制流**。
## 07-20 内置函数与外部函数
- [ ] 待讨论
明确它们是否遵守同样的参数、返回和错误规则,以及无法兼容时如何声明差异。依赖:**内置与标准库、外部互操作**。
## 07-21 语言调用语义与底层约定
- [ ] 待讨论
明确哪些行为属于语言保证,哪些由实现决定;外部调用需要哪些额外约定,避免把栈、寄存器布局误当语言规则。
## 07-22 跨分类一致性验收
- [ ] 待讨论
用代表性程序核对上述规则,并解决与其他分类的冲突;没有未解决的阻塞后完成。
## 当前问题的方案与语言对照
以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。
当前仍是 **07-01:函数能否作为值**,即能否保存、传参、返回,以及通过变量调用。闭包捕获规则仍留在后续任务。
### 五种语言怎样做
下面的例子都假定已经定义了一个“输入整数、返回整数”的 `increment` 函数。取舍是针对我们设计的分析,不代表这些语言的历史设计动机。
| 语言 | 规则与具体行为 | 好处、代价及对我们的启发 |
|---|---|---|
| **Python** | 函数是对象。`f = increment` 保存函数,`f(3)` 调用它;也能放入列表、传参和返回。[官方教程](https://docs.python.org/3/tutorial/controlflow.html#defining-functions) | 行为组合直接;单靠语言运行时的动态检查,部分不合法调用到执行时才发现。**支持函数值,不要求我们采用动态类型或 Python 的对象模型。** |
| **JS** | 函数是可调用的对象。例如 `const f = increment; f(3)`,也能作为参数和结果。[ECMAScript 规范](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-object-type) | 回调与组合方便;接口的正确使用需要额外约束。**函数具有对象属性,是可单独选择的能力,不必随函数值一起引入。** |
| **TS** | 延续 JS 的函数值行为,并增加静态函数类型,例如 `const f: (x: number) => number = increment`。类型标注被擦除,实际执行的是 JS,不会自动获得运行时参数校验。[函数类型](https://www.typescriptlang.org/docs/handbook/2/functions.html)、[类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types) | 能提前检查许多接口错误;需要设计类型兼容规则,且静态检查不能代替外部输入验证。**函数值能力和检查时机可以分开决定。** |
| **Go** | 支持有静态类型的函数值,例如 `var f func(int) int = increment`,随后 `f(3)`;函数也可传参、返回。函数类型变量的零值为 `nil`。[Go 规范](https://go.dev/ref/spec#Function_types) | 调用接口明确;需要处理空函数值等边界。**可以支持函数值,同时保留较直接的签名模型;我们不必继承 `nil`。** |
| **Rust** | 支持保存、传递和返回函数相关的值,但区分函数项、函数指针和闭包。例如 `let f: fn(i32) -> i32 = increment;`。捕获环境的闭包不能直接当作普通 `fn` 指针,通常通过 `Fn` 等接口使用。[Rust 官方书](https://doc.rust-lang.org/book/ch20-04-advanced-functions-and-closures.html)、[函数指针规则](https://doc.rust-lang.org/reference/types/function-pointer.html) | 能明确表达不同调用能力;类型与接口规则更多。**一等函数不要求所有可调用值具有同一种类型或底层表示。** |
这些语言都支持广泛的函数值能力,区别主要在类型、对象能力和环境捕获。**Rust 的类型区分并不意味着它只支持我们下面的 B。**
### 我们当前的三个选项
- **A:函数只作为调用目标。** 可以直接调用,不能作为普通数据保存、传递或返回。规则较少,但通用回调需要其他机制。
- **B:支持受限的函数引用。** 只开放明确的一部分能力,例如仅允许引用静态定义的函数。适合有具体限制目标的语言,需要说明每条限制的理由。
- **C:函数是一等值。** 允许保存、传参和返回,遵守一般的类型与生命周期规则。随后分别决定匿名函数、闭包和函数类型。
**我仍建议 C**:它让排序比较器、事件回调、可替换的处理步骤等接口容易表达,同时保留后续设计空间。
选择 C 后,下面的基础行为应成立:
```text
chosen = increment // 保存,不执行
apply(chosen, 3) // apply 内部调用 chosen,得到 4
return increment // 可以返回已有函数
```
调用非函数应被拒绝;拒绝发生在静态检查还是运行时,依赖类型系统。返回捕获局部变量的函数是否允许,仍待闭包任务决定。
**你选择 A、B,还是 C?**
## 讨论来源
《语言设计 07:函数与调用》,整理日期 2026-10-28。章节编号沿用原清单。