1 Commits

Author SHA1 Message Date
codex-bot 5e185c53e3 备份语言规范、顶级类型与运行时设计草稿 2026-11-05 00:53:52 +08:00
31 changed files with 3594 additions and 64 deletions
+4
View File
@@ -0,0 +1,4 @@
RenderObject
-
+14 -5
View File
@@ -1,12 +1,12 @@
# Endorphin 语言文档
Endorphin 是一门面向云原生应用的编程语言,使用统一的资源与语言模型描述前端界面、数据结构、后端逻辑和 agent。基础内容由平台管理,变量引用资源,开发者和 agent 编写声明、表达式与调用关系,平台解释执行代码,客户端根据资源或结果的类型呈现内容。
Endorphin 是一门面向云原生应用的编程语言,使用统一的对象与资源模型描述前端界面、数据结构、后端逻辑和 agent。类型本身也是对象,Object 与 Type 构成实例化和继承的基础闭环。平台按具体类型管理对象的生命周期,变量引用资源,开发者和 agent 组织对象、表达式与调用关系,客户端根据资源或结果的类型呈现内容。
## 阅读指南
正文按概念的依赖顺序编排。首次阅读从第 1 章开始;查询具体写法时,可以直接进入相应章节。每章包含概念定义、语法、示例和行为说明。
本书为语言设计稿。资源归属 workspace,key 使用 workspace handle 与 namespace 路径;用户以成员角色参与协作。use 形式、整体授权边界和阶段命名等基础约定已经确定。权限操作区分资源编辑与程序使用,函数、类型、数据读取与 UI 的具体写法以本文收录的草案为准。各主题的确定程度统一记录在[规范状态](appendices/specification-status.md),正文不反复叙述设计过程。
本书为语言设计稿。资源归属 workspace,key 使用 workspace handle 与 namespace 路径;用户以成员角色参与协作。权限操作区分资源编辑与程序使用,函数、类型、数据读取与 UI 的具体写法按所标注的设计状态使用。各主题的确定程度记录在[规范状态](appendices/specification-status.md)。
## 正文
@@ -21,16 +21,17 @@ Endorphin 是一门面向云原生应用的编程语言,使用统一的资源
### 第二部分:基础语法
6. [词法结构](guide/06-lexical-structure.md) — 标识符、字面量、符号、标点和注释。
7. [资源、类型与类](guide/07-types-and-classes.md) — 基础常量、统一数值、媒体归一化、类型与 class。
7. [资源、类型与类](guide/07-types-and-classes.md) — 类型与实例、资源 atom、具体类型与 class;[Object 与类型系统](guide/07-top-level-types/README.md)解释 Object/Type 闭环、实例化线、继承线及资源 ID。
8. [表达式与绑定](guide/08-expressions-and-bindings.md) — 求值、运算、成员访问、let 与可变资源引用。
9. [函数与调用](guide/09-functions-and-calls.md) — 函数声明、返回值和跨 namespace 组合。
### 第三部分:应用用法
10. [数据读取](guide/10-data-access.md) — 通过类型取得数据及结果状态。
11. [资源访问与呈现](guide/11-resource-access-and-presentation.md) — 查看函数、参数就绪、调用结果与按类型呈现。
11. [资源访问与呈现](guide/11-resource-access-and-presentation.md) — 查看与调用、按类型呈现,以及平台对象、本地副本与跨端同步。
12. [UI 组件](guide/12-ui-components.md) — Column、Row、Spacer 和 Text 的参数与效果。
13. [Agent](guide/13-agents.md) — 共有成员、tools、memory、state、路由、中断与上下文管理。
14. [交互式会话(REPL)](guide/14-repl.md) — 会话上下文、输入求值、对象查看与远程状态的设计提案。
## 附录
@@ -40,13 +41,21 @@ Endorphin 是一门面向云原生应用的编程语言,使用统一的资源
- [应用领域](appendices/application-domains.md) — UI、业务逻辑、数据访问和 Agent 的适用范围。
- [规范状态](appendices/specification-status.md) — 已确定约定、语法提案及未定义的边界。
### 补充参考
- [其他语言的关键词分类与逐词说明](appendices/language-keywords.md) — Python、JavaScript、TypeScript、Java、C、C++、C#、Go、Rust、Swift、Kotlin、Julia 的关键词用途与区别,供跨语言学习和设计比较查阅。
- [12 门语言的执行模型与生命周期](appendices/language-runtime-lifecycles.md) — 逐门比较执行入口、定义与上下文、任务调度、等待恢复及资源清理。
- [框架如何接管代码执行](appendices/framework-runtime-lifecycles.md) — 从具体动作追踪普通进程、FastAPI、Spring Boot、Unity、React 与 Node/Chromium,并整理 Endorphin 执行模型的研究维度。
比较执行机制时,先阅读统一分析模板,再从熟悉的语言进入对应框架案例;这些外部机制不自动成为 Endorphin 的语言规则。
## 记法
源码以 `endorphin` 代码块展示,文法以 `ebnf` 代码块展示。源码中的关键字和名称区分大小写;语言阶段名称固定为 `Preflight` 和 `inflight`。
“代码归属”写在代码块之前,用于说明外部上下文,不属于源码。函数体片段会注明使用位置,资源访问与界面结构示意使用 `text` 代码块,不表示新增源码语法。示例中的用户和 namespace 为示意名称。
正文的函数示例围绕商品定价展开:`atelier:shop.pricing` 提供定价逻辑,`market:shop.checkout` 组合它,`market:shop.ui` 表达界面;数据读取示例使用 `atelier:shop.data`。atelier 与 market 是 workspace handle,后面的路径表示代码组织,不指定执行位置。
函数示例围绕商品定价展开:`atelier:shop.pricing` 提供定价逻辑,`market:shop.checkout` 组合它,`market:shop.ui` 表达界面;数据读取示例使用 `atelier:shop.data`。atelier 与 market 是 workspace handle,后面的路径表示代码组织,不指定执行位置。
## 文档维护入口
+4 -2
View File
@@ -4,7 +4,9 @@
## 独立代码段
代码分别存储为独立代码段,每段关联一个归属 workspace 和至少一级 namespace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;编写或修改代码的用户身份另行记录。
代码分别存储为独立代码段,以资源 ID 识别并关联归属 workspace。S3 承担代码内容的存储职责,索引维护 namespace key 与代码段的成员关系;一段代码可以具有多个命名入口,编写或修改代码的用户身份另行记录。
移除 namespace 成员入口不删除仍被其他保留程序引用的代码段。资源 ID、存储对象键与 namespace key 分别表达逻辑身份、存储位置和命名入口,具体引用语义见[资源引用](../guide/07-top-level-types/references.md)。
源码文件不作为代码身份或 module 边界。本书中的 Markdown 文件是文档章节,不对应语言中的源码组织单位。
@@ -31,7 +33,7 @@ S3 对象键不是语言中的 namespace key。bucket 名、对象键和存储
## namespace 制
namespace 同时表达归属与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。
namespace 提供归属 workspace 内的组织与查找位置,使业务函数、类型、界面逻辑和 agent 定义遵循一致的组织模型。第一级与后续层级具有相同语义。
基础内容也纳入资源归属方向,但本附录的 S3 代码段约定不自动规定媒体、GIS 数据、对象或 agent 记忆的存储后端。代码视图与完整资源集合的区别见[namespace](../guide/03-namespaces.md)。
+8 -2
View File
@@ -1,6 +1,12 @@
# 形式文法
本附录集中列出正文采用的文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果由相应章节定义。各主题的确定程度见[规范状态](specification-status.md)。
本附录集中列出文法草案。文法说明可表达的源码结构;名称、类型、可见性与执行效果遵守相应语义约束。各主题的确定程度见[规范状态](specification-status.md)。
[对象类型与构造](../guide/07-top-level-types/README.md)采用候选的自身类型标注、trait、容器、任务及 Agent 实例记法。以下 EBNF 只覆盖列出的语法范围,不穷尽对象构造形式。
Object 是继承根,Object 和 Type 都是 Type 的实例,Type 继承 Object。实例化线与继承线属于类型语义;typeOf、basesOf 等反射接口与显式继承语法仍待定义。
class、agent 等构造入口自身是对象。以下产生式中的文字终结符描述候选构造记法,不据此将这些名称定为保留关键字;入口的类型、名称解析及调用语法尚待定义。
## EBNF 记法
@@ -97,7 +103,7 @@ primary = identifier | string | number | symbol
| "(", expression, ")" ;
```
成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。正文采用同级二元算术运算从左到右组合的规则。
成员访问与调用先于一元负号,一元负号先于乘除,乘除先于加减。同级二元算术运算从左到右组合。
此处能表达成员调用,不代表某个类型自动拥有相应成员。数据读取提案使用同一套表达式文法,没有单独的 get 关键字。
+468
View File
@@ -0,0 +1,468 @@
# 框架如何接管代码执行
框架通过保存定义、关联入口、管理活动状态和调用用户函数来组织执行。语言、执行引擎、宿主和框架的职责分别说明,才能判断一段代码何时运行、在哪运行,以及哪个实体一直存续。基础结构见[12 门语言的执行模型与生命周期](language-runtime-lifecycles.md),词法用途见[关键词手册](language-keywords.md)。
资料核对日期:2026-10-13。本文以普通 hosted C 进程、CPython/FastAPI/ASGI、Java/Spring Boot/Spring MVC、Unity 6.0,以及 TypeScript/React/Node/Chromium 的指定路径为案例。持续更新的官方文档与实现源码用于说明相应机制,不代表所有历史版本。代码展示预期行为,未作为执行日志;框架的开发模式、配置和替代后端会改变部分时序。
## 先确定每一层回答什么
| 层 | 职责 | 典型证据 |
| --- | --- | --- |
| 语言 | 调用、作用域、暂停、异常、类型等的语义 | Python、Java、C#、ECMAScript 等规范 |
| 编译或构建工具 | 检查和转换源码,准备可执行逻辑 | TypeScript 类型擦除、JSX 转换、C# 编译 |
| 执行引擎或原生执行环境 | 推进当前代码并维护必要执行状态 | CPython、JVM、V8、Mono、原生机器码 |
| 宿主 | 应用入口、I/O、系统事件、线程或事件循环、呈现能力 | ASGI 服务器、Servlet 容器、Node、浏览器、Unity |
| 库或框架 | 入口映射、应用状态、组件或请求的组织 | FastAPI 路由、Spring bean、React 组件树 |
这些是职责边界,不要求每层都是一个独立进程,也不保证每个产品只处在一层。Unity 同时提供引擎宿主与组件管理;Node 包含 V8、原生绑定及 libuv 等协作部分;浏览器还有渲染、网络及多进程组织,不能缩减成 V8 本身。
注册建立“条件与逻辑”的关系。外部事件或明确调用进入入口;调度机制安排执行机会;引擎执行本次函数。框架也会执行自己的代码,它调用用户函数时通常仍使用语言的普通调用机制。
## 路径一:C 普通进程
### 从启动到返回
这是一个完整的 hosted C 示例,不依赖应用框架。预期输出 `42` 并正常返回成功状态。
```c
#include <stdio.h>
static int price(int base) {
return base + 2;
}
int main(void) {
int result = price(40);
printf("%d\n", result);
return 0;
}
```
```text
启动程序
→ 操作系统及实现的启动代码准备执行环境
→ 进入 main
→ 用户调用 price,当前线程进入该函数
→ price 返回 42,继续 main
→ printf 产生输出
→ main 正常返回,执行正常退出流程
```
`price` 的函数定义不因“程序已经启动”而自己反复执行。这里没有应用任务队列:下一步由当前控制流确定;CPU 最终执行编译后的指令,OS 仍可调度执行线程。[C23 草案的 hosted 启动与终止](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf)
### 谁持有状态
| 实体 | 保存的信息 | 结束方式 |
| --- | --- | --- |
| 程序及静态存储 | 可执行代码与长期数据 | 正常退出或进程终止 |
| `main` 调用 | `result`、当前进度及调用关系 | 返回 |
| `price` 调用 | `base` 及临时计算 | 返回 42;典型原生调用状态结束 |
| 输出设施 | 缓冲和 OS 资源 | 库及退出协议处理 |
实际 ABI 可以用栈、寄存器和内联等实现调用。语言规定调用结果,具体执行布局由实现决定。添加 GUI 库或 HTTP 服务器后,入口还会增加库管理的事件关系;C 语言本身没有因此改变。
## 路径二:FastAPI
### 注册路由与处理请求是两个动作
以下内容是可交给 ASGI 服务器加载的 Python 模块。`sleep` 用于展示可暂停等待,不代表真实数据库实现。预期请求 `GET /price?base=40` 得到 JSON 数据 `{"price":42}`。
```python
import asyncio
from fastapi import FastAPI
app = FastAPI()
@app.get("/price")
async def price(base: int = 40):
await asyncio.sleep(0.01)
return {"price": base + 2}
```
加载模块时执行导入、创建 `app`、创建函数及应用装饰器;装饰器把路径、方法和函数等关联起来。它不在注册时替未来每个请求执行 `price` 函数体。请求进入后,框架才使用这份关联选择处理函数。
服务器以 Uvicorn 为例;事件循环可使用 asyncio 或其兼容实现,而非只能使用 CPython 中某个唯一固定循环。[Uvicorn 事件循环选择](https://uvicorn.dev/concepts/event-loop/)
### 一次请求经过哪些层
```mermaid
sequenceDiagram
participant Client as 客户端
participant Server as ASGI 服务器与事件循环
participant App as FastAPI 与 Starlette
participant Handler as 用户 price 协程
Client->>Server: GET /price?base=40
Server->>App: 调用应用:scope、receive、send
App->>App: 路由、参数与依赖处理
App->>Handler: 调用并推进协程
Handler->>Server: 可暂停等待
Note over Handler: 局部状态和继续关系被保留
Server->>Handler: 条件满足后安排继续
Handler-->>App: 返回字典
App->>Server: 生成并发送响应事件
Server-->>Client: HTTP JSON 响应
```
图示压缩了中间件和序列化细节。ASGI 的 HTTP `scope` 对应一次请求,WebSocket `scope` 则可贯穿整个连接;HTTP keep-alive 不把多个请求合并为同一次处理函数调用。服务器提供协议事件,应用通过可等待的 `receive`/`send` 接收与发送。[ASGI 规范](https://asgi.readthedocs.io/en/latest/specs/main.html)
| 结构 | 保存的信息 | 管理者与存续 |
| --- | --- | --- |
| 模块及 `app`、路由定义 | 应用配置和入口映射 | 模块/框架,跨多个请求 |
| 请求 scope、Request、依赖求值状态 | 方法、路径、头、输入及本次依赖 | 服务器/Starlette/FastAPI,围绕请求 |
| coroutine 继续状态 | `base` 等局部状态、等待后的进度 | Python 执行机制,围绕本次处理 |
| Task 及事件循环的等待管理 | 活动状态、等待结果和恢复安排 | ASGI 服务器选定的异步环境 |
| 响应对象与输出事件 | 状态码、头及 body | 框架/服务器,直至相应发送流程结束 |
### 同步函数和异步函数的执行位置
FastAPI 通过框架调用的普通 `def` 路由函数和同步依赖,通常交给外部线程池;`async def` 路由在异步调用链中推进。这个区别只适用于它负责调用的设施:用户自己在 async 路由中直接调用普通辅助函数,仍是普通同步调用,不自动被挪到线程池。异步函数中的 CPU 循环或阻塞 I/O 仍能阻碍事件循环。[FastAPI 的技术说明](https://fastapi.tiangolo.com/async/#very-technical-details)
### 应用、请求和依赖分别清理
应用的 `lifespan` 上下文管理共享资源:进入部分用于应用接收请求前的准备,退出部分用于关闭。带 `yield` 的依赖围绕更小的工作范围获取和释放资源。当前文档区分 `scope="function"` 的函数退出清理与 `scope="request"` 的响应发送后清理;不要把两者写成一个固定时间点。[应用 lifespan](https://fastapi.tiangolo.com/advanced/events/)、[带 yield 依赖的 scope](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope)
处理函数返回不意味着应用退出;请求结束不意味着共享连接池必须销毁。失败进入异常处理路径,取消及断连的传播要结合服务器、中间件和被等待操作判断,不能承诺客户端断开后所有业务效果立即停止或回滚。
## 路径三:Spring Boot
### 从入口启动容器
基线是使用 Spring MVC 的应用及嵌入式 Servlet 容器,Tomcat 可作为例子。Spring Boot 组织启动与配置;Spring 的 `ApplicationContext` 管理 bean;Servlet 容器接入 HTTP;JVM 执行 Java 方法。这些不是同一个生命周期。
下面是 `example.pricing` 包中的 `PriceApplication.java` 示例,前提是项目具有相应 Spring Boot Web 依赖。预期请求 `GET /price?base=40` 返回包含 `price: 42` 的 JSON 对象。
```java
package example.pricing;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class PriceApplication {
public static void main(String[] args) {
SpringApplication.run(PriceApplication.class, args);
}
@RestController
static class PriceController {
@GetMapping("/price")
public Map<String, Integer> price(
@RequestParam(name = "base", defaultValue = "40") int base) {
return Map.of("price", base + 2);
}
}
}
```
启动时由容器读取配置、发现并创建所需 bean、注入依赖及调用相应初始化设施。映射注解是供框架使用的元数据;Java 的 `@GetMapping` 拼写不是新增 Java 关键词,声明它也不等于马上处理请求。[Spring Boot 的启动](https://docs.spring.io/spring-boot/reference/features/spring-application.html)、[bean 与依赖注入](https://docs.spring.io/spring-boot/reference/using/spring-beans-and-dependency-injection.html)
### 请求怎样进入 controller
```text
HTTP 请求
→ Servlet 容器接入并安排处理
→ Filter 等链路
→ DispatcherServlet
→ HandlerMapping 查找匹配的处理器
→ HandlerAdapter 配合参数解析等设施调用 controller 方法
→ JVM 推进本次 Java 调用
→ 返回值处理及消息转换形成 JSON 响应
→ 容器写回客户端
```
这里选择 `@RestController` 的数据响应路径;返回视图名的 controller 还会涉及视图解析。URL 没有一个“执行 Java”的特殊开关,服务端配置的分派逻辑决定产生响应的方法。[DispatcherServlet](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet.html)、[请求处理序列](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/sequence.html)
| 结构 | 保存的信息 | 管理者与存续 |
| --- | --- | --- |
| JVM 的类、方法元数据 | 编译后的 Java 逻辑 | JVM/类加载器 |
| bean definition 与 ApplicationContext | 创建配方、依赖关系及受管理实例 | Spring,跨请求或按配置的 scope |
| 请求映射与 handler 元数据 | 路径、方法、参数及调用入口 | Spring MVC,跨请求 |
| Servlet 请求/响应及分派状态 | 本次 HTTP 数据和处理关联 | 容器及框架,围绕一次请求 |
| JVM 方法 frame | 参数、局部变量及方法进度 | 本次 Java 调用 |
默认 singleton bean 在容器内被复用,不是每个请求都创建一个 controller。方法 frame 是本次调用的状态;把请求数据存入复用实例字段会涉及并发访问。这是实例存续与请求存续不同带来的后果。prototype 等 scope 的退出管理也有不同保证,不能认为所有 bean 都由容器完整管理至销毁。[Spring bean scope](https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html)
### 初始化、请求返回与关闭
Spring 可以调用 `@PostConstruct`、初始化接口或配置的 init 方法;正常关闭时可调用 `@PreDestroy` 等销毁设施。`Lifecycle`/`SmartLifecycle` 还表达受管理活动的启停。回调由容器在相应条件下调用,不由 Java GC 替代;具体 bean scope 的管理保证需要分别核对。[Spring bean 生命周期](https://docs.spring.io/spring-framework/reference/core/beans/factory-nature.html)
请求方法返回后应用继续存续。Boot 的正常退出支持关闭 ApplicationContext 的安排;强制终止不能被当作所有清理钩子都会执行的正常关闭。[Spring Boot 应用退出](https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.application-exit)
### WebFlux 是另一种请求模型
Spring Boot 并不只代表 Servlet 阻塞模型。WebFlux 使用非阻塞契约、响应式组合及服务器适配;通常用较少的事件循环工作线程推进活动,和 MVC 常见的阻塞处理假设不同。`Mono`/`Flux` 保存或组合数据流协议,不等同于每个请求专属的一条 JVM 调用栈。这里的 Reactor `Mono` 是响应式库类型,与 Unity 的 Mono 执行后端无关。MVC 也能使用异步设施,不能把二者概括成“Java 一定阻塞”和“Java 一定事件循环”。[Spring WebFlux 的并发模型](https://docs.spring.io/spring-framework/reference/web/webflux/new-framework.html)
## 路径四:Unity
### 执行后端与阶段安排是两个问题
Unity 的 C# 脚本通常先编译为 IL 等内容。Mono 后端提供托管执行与 JIT;IL2CPP 将 IL 转为 C++ 再编译为原生代码。不能直接把 Unity 写成桌面 CoreCLR 应用。无论采用哪条后端路径,引擎依然承担场景与组件管理,以及 PlayerLoop 的阶段调用安排。[Unity 脚本后端](https://docs.unity3d.com/6000.0/Documentation/Manual/scripting-backends.html)
```text
开发准备:C# 源码 → IL → Mono 执行路径/IL2CPP 原生编译路径
应用运行:Unity 启动与场景准备
→ 建立 GameObject 与组件实例及关系
→ 根据对象活动、组件启用与阶段规则调用事件函数
→ PlayerLoop 推进输入、物理、脚本更新及其他系统
→ 场景卸载、禁用或销毁触发相应处理
```
PlayerLoop 是引擎的一组系统阶段,还能通过相关 API 定制;并不是每一帧把项目里所有 C# 函数都运行一次。[Unity 事件执行顺序](https://docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html)
### 哪些回调在什么条件下进入
| 入口 | 管理条件 | 不能推出的结论 |
| --- | --- | --- |
| `Awake` | 组件实例加载、对象激活等符合条件的初始化,一实例调用一次 | 不是所有不活动对象都在场景加载时立即执行,也不是 C# 普通构造器 |
| `OnEnable` | 对象活动且组件启用时 | 不是一生只调用一次,可因再次启用进入 |
| `Start` | 启用后首次更新前的一次初始化 | 不保证与 Awake 同帧;禁用时可能延后 |
| `FixedUpdate` | 固定时间步的物理更新安排 | 每个显示帧可能零次、一次或多次 |
| `Update` | 符合条件的脚本帧更新 | 不是全部数据对象的通用钩子 |
| `LateUpdate` | 在 Update 后的相应阶段 | 不代替任意线程的同步协议 |
| `OnDisable` | 组件或对象退出启用活动等相应情形 | 禁用和销毁不是同一状态 |
| `OnDestroy` | 满足条件的组件或对象销毁 | 有适用边界;强制退出不能保证执行 |
条件详见 [Awake](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Awake.html)、[OnEnable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnEnable.html)、[Start](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Start.html)、[FixedUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.FixedUpdate.html)、[Update](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.Update.html)、[LateUpdate](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.LateUpdate.html)、[OnDisable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDisable.html)、[OnDestroy](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MonoBehaviour.OnDestroy.html)。
以下是应保存为 `PriceLabel.cs` 并挂在活动 GameObject 上的组件例子。这里用日志观察执行,不代表 UI 的正式绘制实现。
```csharp
using UnityEngine;
public class PriceLabel : MonoBehaviour
{
private int price;
private void Awake() { price = 42; }
private void OnEnable() { Debug.Log("enabled"); }
private void Start() { Debug.Log(price); }
private void Update() { /* 每次符合条件的更新处理 */ }
private void OnDisable() { Debug.Log("disabled"); }
}
```
在常规初始化条件下,实例准备→Awake→OnEnable→Start→后续 Update。重新禁用再启用,可以再发生 OnEnable;这不意味着 price 字段被重新创建或 Start 再次执行。同类不同对象的调用顺序不能仅凭源码文件排列推断。
### 哪些状态跨帧存在
| 结构 | 保存的信息 | 管理者与存续 |
| --- | --- | --- |
| 场景、GameObject 与组件关系 | 对象组织、活动及启用状态 | Unity 引擎,跨帧 |
| 脚本实例及字段 | `price` 等长期组件状态 | 托管对象及引擎对象关联,跨回调 |
| 每次 Update 等的方法调用状态 | 本次局部变量和当前进度 | 执行后端,一次回调 |
| IEnumerator 状态机与协程等待记录 | 跨 yield 的局部数据、继续位置及等待条件 | 编译器表示及 Unity 协程调度 |
| 引擎资源与托管引用 | 场景对象、资源及引用关系 | 引擎销毁和托管回收分别处理 |
普通 `Update` 返回后,下帧是另一次函数调用;Unity 协程 `yield return` 后则由引擎按等待条件继续迭代状态。`StartCoroutine` 不自动创建后台线程;同步耗时计算仍可占用主线程。停止条件也取决于对象、组件及协程 API,不能把“组件 disabled”当成所有任务统一取消协议。[Unity 协程](https://docs.unity3d.com/6000.0/Documentation/Manual/Coroutines.html)
## 路径五:React
### 构建不是应用运行的中间调度层
```text
开发及构建:
TS/TSX 源码
→ 类型检查、类型处理、JSX 转换及模块处理
→ 供目标宿主执行的 JavaScript
运行:
浏览器:启动 JS → React 组织组件计算 → DOM 提交 → 浏览器呈现
服务器:Node 执行 JS → React 服务端渲染 → 输出 HTML 等响应
```
转换可以分散在 TypeScript、其他转换器和打包工具中;JSX 也可以先被保留。构建工具运行在 Node,不证明组件随后一定在 Node 执行。React 是正在被执行的库代码,会组织用户组件及更新的调用;TS 类型通常已擦除。[TypeScript 的类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types)、[JSX 转换模式](https://www.typescriptlang.org/docs/handbook/jsx.html)
### 浏览器首次显示与一次点击
下面是客户端入口 TSX 的例子,前提是页面中有 `id="root"` 的容器,且构建环境提供 React、React DOM 和相应类型声明。它是普通客户端渲染,不含 SSR。
```tsx
import { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
function Price() {
const [price, setPrice] = useState(42);
useEffect(() => {
const previousTitle = document.title;
document.title = `Price: ${price}`;
return () => { document.title = previousTitle; };
}, [price]);
return <button onClick={() => setPrice(p => p + 1)}>{price}</button>;
}
createRoot(document.getElementById("root")!).render(<Price />);
```
预期首次按钮显示 42,点击后显示 43;提交后的 Effect 同步相应标题。示例的非空断言不构成运行时容器创建,HTML 必须实际提供该节点。调用 root.render 提交渲染请求,也不能据此认为调用返回时所有 DOM 和 Effect 工作已经完成。[createRoot 与 render](https://react.dev/reference/react-dom/client/createRoot)
| 步骤 | 谁进入或调用 | 保存或使用的状态 |
| --- | --- | --- |
| 加载入口 JS | 浏览器的脚本加载与求值机制 | JS 模块、函数及 React 库 |
| 首次 render 请求 | 入口调用 React root API | root、更新及组件关系 |
| 组件计算 | React 调用 `Price` | 本次调用的局部值,React 持有的 Hook 状态 |
| commit | React 调用 DOM 等宿主接口 | 已提交的树及 DOM 关系 |
| Effect setup | React 按 Effect 规则安排 | 依赖和返回的 cleanup |
| 用户点击 | 浏览器事件分派进入 React 事件处理,再调用用户处理逻辑 | 事件、组件关联及更新请求 |
| 后续更新 | React 处理状态更新,再组织 render/commit | 新状态,旧依赖及新依赖 |
| 卸载 | root 或组件树操作使组件退出 | Effect cleanup、宿主节点及关联清理 |
render 是计算下一份界面描述,commit 才将相应变化应用到宿主。组件函数可以被多次调用;应保持渲染计算纯净,不能把“函数被调用一次”当作“一次业务操作已经提交”的保证。[React render 与 commit](https://react.dev/learn/render-and-commit)、[组件与 Hook 的纯度要求](https://react.dev/reference/rules/components-and-hooks-must-be-pure)
### 状态为什么没有随组件函数返回而消失
React 持有组件关系及 Hook 状态,组件函数每次调用读取当前状态。普通局部变量随调用建立,`useState` 管理的状态则与 React 管理的组件身份关联,不能当作每次新建的普通局部值。[React 状态的保留与重置](https://react.dev/learn/preserving-and-resetting-state)
| 结构 | 职责 | 所属层 |
| --- | --- | --- |
| JS 函数、闭包和本次调用状态 | 执行组件计算及事件函数 | JavaScript 引擎 |
| React element 等界面描述 | 表达本次计算所得结构 | React 库数据 |
| Fiber 与 root | 组件工作、父子关联、已保存状态、更新及待处理工作 | React 当前协调实现 |
| Hook 状态与 Effect 记录 | 状态、依赖及 cleanup 关联 | React 管理结构 |
| DOM 节点与事件设施 | 浏览器中的宿主呈现及交互 | 浏览器 |
Fiber 是实现结构,源码包含子节点、相邻节点、更新队列和保存状态等信息。它不等于 V8 调用栈,也不是所有 React API 使用者必须直接创建的对象;字段和布局不是稳定应用 API。[React 实现中的 Fiber 类型](https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactInternalTypes.js)
### React Hook 与 Unity 阶段回调的差别
`useState`、`useEffect` 等普通 Hook 必须服从顶层调用与顺序约束,它们不是可以任意在条件中增删的动态回调列表。`useEffect` 记录的 setup/cleanup 与依赖变化关联;`useState` 则管理状态,并不代表事件监听。特殊的 `use` API 有不同的调用规则,不能用“所有 use 开头函数都绝对相同”概括。[Hook 规则](https://react.dev/reference/rules/rules-of-hooks)、[use API](https://react.dev/reference/react/use)
Effect 在组件提交后按相关规则同步外部系统;依赖变化时先清理旧关联,再建立新关联,卸载时清理。开发 Strict Mode 会增加用于检查的 setup/cleanup 周期。Effect 与浏览器实际绘制的先后不能简单固定为“每次 paint 之后”;`useEffect` 与 `useLayoutEffect` 的契约不同。[useEffect 的时序与边界](https://react.dev/reference/react/useEffect)
Unity 主要用引擎命名阶段选择符合条件的组件回调;React 主要用更新、组件计算、提交和依赖关联组织 UI。React 不要求组件每个显示帧都重新计算,也没有为每个普通函数自动提供 Awake/Update。
### 可选的服务端渲染与 hydration
```mermaid
sequenceDiagram
participant Browser as 浏览器进程
participant Server as Node 服务器进程
participant SSR as 服务器 React 渲染
participant ClientReact as 浏览器 React
Browser->>Server: 页面请求
Server->>SSR: 调用服务端渲染入口
SSR-->>Server: HTML 流等结果
Server-->>Browser: HTTP 响应与后续资源
Browser->>Browser: 解析 HTML 并加载客户端 JS
Browser->>ClientReact: hydrateRoot 等入口
ClientReact->>Browser: 关联交互逻辑与已有 DOM
```
`renderToPipeableStream` 是 Node 流环境的一条 React 服务端输出路径;浏览器的 `hydrateRoot` 接管已有的服务端 HTML 并建立客户端交互。初始渲染结果要符合 hydration 的一致性要求,不能把服务器函数对象、闭包或堆地址当成直接转移到浏览器的状态。[服务端流渲染](https://react.dev/reference/react-dom/server/renderToPipeableStream)、[hydrateRoot](https://react.dev/reference/react-dom/client/hydrateRoot)
服务端和客户端分别拥有自己的 JS 执行环境与对象。Effects 不在服务端渲染时运行;需要客户端的交互逻辑仍由浏览器加载和执行。SSR、React Server Components、服务器函数与框架路由是不同机制;本节追踪传统 SSR/hydration,不把其他机制默认叠加进去。
## Node 与 Chromium
### 请求得到什么与客户端怎么使用分别决定
服务端先按路由或静态资源配置生成响应,客户端再按请求用途、响应信息和自己的规则使用内容。URL 的后缀不能单独决定代码是在服务器执行还是在浏览器执行。
| 动作 | 服务端可能怎样生成响应 | 浏览器接收后的典型路径 |
| --- | --- | --- |
| 导航到页面 URL | 静态 HTML 或程序生成 HTML | 导航及文档解析、样式、布局和呈现 |
| 页面引用 `<script src="/app.js">` | 读取文件或程序生成 JS | 脚本机制在满足加载、类型及策略条件后安排执行 |
| `fetch("/app.js")` | 也可能是同一份 JS 字节 | 得到 Response,读取为文本不自动执行该文本 |
| `fetch("/price")` 并解析 JSON | 服务端处理函数计算再序列化 | 创建本地 JS 数据;用户代码决定怎样更新界面 |
脚本加载和执行规则由 HTML 宿主机制规定;Fetch 返回响应的 API 本身不包含“自动把响应当脚本执行”。直接打开 JS 或 JSON 资源时,显示或下载还受导航、媒体类型和响应头等规则影响,不能假定所有浏览器都采用相同展示界面。[HTML script 规则](https://html.spec.whatwg.org/multipage/scripting.html#the-script-element)、[Fetch 方法](https://fetch.spec.whatwg.org/#fetch-method)
服务器即使返回 JSON,浏览器也可以显示文本;具有特定应用含义的按钮、图表等需要客户端程序、HTML 或相应查看器的呈现规则。JSON 的数据结构本身不会自动定义完整应用 UI。
### 浏览器与 Node 的任务管理
| 维度 | Chromium 中的页面 | Node 应用 |
| --- | --- | --- |
| 入口 | 导航、脚本/模块、事件、控制台求值等 | 入口模块、REPL、服务器及其他 API 回调 |
| 系统事件 | 用户交互、网络、定时器、页面生命周期等 | 网络、文件、定时器、进程等 |
| 调度组织 | HTML 任务来源、任务队列、微任务检查点及渲染机会 | libuv 阶段、Node 回调边界及微任务处理 |
| 呈现 | DOM、样式、布局、绘制等浏览器设施 | 默认没有页面 DOM 和浏览器绘制阶段 |
| 长期状态 | 文档、DOM、监听关联、JS 环境、框架状态 | 模块、服务器、连接、监听关联、JS 环境 |
| 实际执行 JS | V8 | V8 |
浏览器规范中的正式概念是 task;“宏任务”是常见教学叫法。不能把浏览器描述成唯一全局 FIFO 队列。微任务检查点会处理新加入的微任务,渲染还要符合渲染机会条件。[HTML 事件循环](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)
Node 的 timers、poll、check 等阶段来自宿主机制;`setImmediate` 和 `process.nextTick` 不是 ECMAScript 关键词或 V8 自带的全部循环。`nextTick` 的先后还要考虑调用上下文及模块求值方式,不能承诺它在所有情境绝对先于一切 Promise 工作。[Node 阶段与 nextTick](https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick)
V8 提供上下文、代码执行和微任务相关能力,宿主通过嵌入接口配合调度。因此“V8 完全没有任何队列”也不准确;完整 I/O 与应用事件循环仍不能统称为 V8。[V8 嵌入说明](https://v8.dev/docs/embed)、[V8 MicrotaskQueue API](https://v8.github.io/api/head/classv8_1_1MicrotaskQueue.html)
### 同步调用、事件和 REPL 三种入口
Node HTTP 服务器把请求函数登记到服务器的 request 事件关系中;收到请求后,宿主和服务器设施进入回调,V8 执行用户 JS。运行到普通 `helper()` 调用时则立即进入该函数,不等待另一个 HTTP 事件。监听器是长期关联,每次调用状态是短期上下文。[Node HTTP request 事件](https://nodejs.org/api/http.html#event-request)
Node REPL 管理输入流、求值上下文、结果输出及会话关闭等;浏览器控制台在所选页面或 frame 的环境中求值,能接触对应 DOM 等宿主对象。它们可以使用同一引擎的求值能力,但会话、绑定规则、可用 API 和后台活动不同。REPL 等输入时,进程不需要一直忙跑一段用户 JS 循环。[Node REPL](https://nodejs.org/api/repl.html)、[Chrome 控制台执行 JavaScript](https://developer.chrome.com/docs/devtools/console/javascript)
## 五条路径放在同一张表里
| 路径 | 触发与入口选择 | 执行的推进者 | 跨执行保留的主要状态 | 普通工作结束 |
| --- | --- | --- | --- | --- |
| C 普通进程 | 启动入口、用户调用 | 原生代码及 OS 线程调度 | 程序数据,调用期间的状态 | 返回或退出 |
| FastAPI | 服务器接入、框架路由及依赖 | CPython、选定异步环境或线程池 | app、路由、请求、Task/协程等待状态 | 响应及相应范围清理 |
| Spring MVC | Servlet 容器、DispatcherServlet | JVM 与容器执行安排 | bean、映射、请求及方法状态 | 返回响应;容器继续存续 |
| Unity | 引擎状态与 PlayerLoop 阶段 | Mono/IL2CPP 路径及引擎 | 场景、组件字段、协程等待记录 | 回调返回、禁用或销毁分别发生 |
| React 浏览器 | root 更新、状态变化和事件 | React 组织调用,V8 执行,浏览器呈现 | 组件关系、Hook、更新、Effect、DOM | 计算完成、提交和卸载分别发生 |
钩子表达触发关系,调度器安排工作,解释器或其他执行机制推进代码;数据结构保存跨这些动作的关系。状态与迁移规则、归属与释放规则则决定哪些动作合法,以及活动何时结束。它们不能只用“有一个循环”替代。
## 对 Endorphin 执行模型的设计分析
本节提出研究维度及验证场景,不确认新的语法、原生任务类型或调度 API。现有语言决定仍以 [Preflight 与 inflight](../guide/05-preflight-and-inflight.md)、[函数与调用](../guide/09-functions-and-calls.md)、[Object 与类型系统](../guide/07-top-level-types/README.md)、[资源访问与呈现](../guide/11-resource-access-and-presentation.md)、[REPL 提案](../guide/14-repl.md)和[规范状态](specification-status.md)为准。
### 先描述可观察的执行契约
| 维度 | 需要形成的明确契约 | 可用的验证场景 |
| --- | --- | --- |
| 定义与活动 | 定义准备、对象创建、调用开始分别由什么动作发生 | 查看函数或导入是否触发业务调用 |
| 执行入口 | 显式调用、REPL 输入、界面事件和平台触发怎样进入 | 提交参数后何时真正执行定价函数 |
| 一次执行的单位 | 本次调用及其子调用、等待和结果如何关联 | 同一函数同时接受两个不同输入 |
| 上下文 | 代码与依赖、输入、局部状态、进度、结果接收方保存在哪里 | 等待后继续使用原来的输入 |
| 顺序与更新边界 | 哪些工作必须有序,何时发布可观察结果 | 同一事件引起两个更新,界面看到什么 |
| 等待与继续 | 保留本次状态、等待条件、恢复入口与失败传播 | 数据未就绪后继续执行,而非重复业务写入 |
| 并发与隔离 | 同一对象上的活动如何协调,哪些状态可共享 | 两次执行同时更新同一个运行对象 |
| 取消与归属 | 谁能结束活动,子活动和资源如何跟随 | REPL 关闭或 UI 消失后仍在等待的计算 |
| 位置与权限 | 平台怎样决定执行位置和有效能力 | 同一函数被不同身份使用,跨端对象如何关联 |
| 清理与保存 | 活动结束、资源解除、结果留存和对象回收分别何时发生 | 查看历史结果不重放计算,订阅结束能释放关联 |
执行记录可以引用平台对象,但数据对象、函数定义、调用状态、结果句柄、触发关联的职责仍需区分。拥有平台 ID 并不自动意味着需要执行;存储局部变量也不自动意味着具备跨进程恢复能力。持久化正在执行的状态还涉及代码版本、外部操作及恢复边界,不能从“状态可保存”直接推出可靠重启。
### 用一条轨迹检查规则是否完整
下面是研究用的行为轨迹,不是 Endorphin 源码或新增 API。
```text
定义已准备
→ 用户明确提交一组输入
→ 建立本次执行及有效上下文
→ 获得执行机会并进入函数
→ 遇到未就绪操作,保留进度与等待关联
→ 条件满足后再次获得执行机会
→ 从继续位置推进,交付结果或失败
→ 解除本次活动资源;按规则保留结果或关联
```
这条轨迹至少能区分“输入还没准备好”“已经执行但正在等待”“已经完成而结果仍被查看”。如果界面重新呈现结果不应重新运行写入,就需要明确结果查看与调用触发的边界;如果不允许自动重试,就不能以重算替代恢复。
### 再选择队列与钩子的组织方式
以下是设计比较,不是已采用方案。
| 候选组织方式 | 适合表达的要求 | 必须另外处理的边界 |
| --- | --- | --- |
| 直接同步调用 | 明确调用关系及立即返回 | 长时间运行、等待及并发活动 |
| 固定阶段回调 | 稳定周期或固定阶段的工作 | 不活动对象、阶段顺序及启停规则 |
| 事件订阅 | 按事件选择处理逻辑 | 订阅所有者、取消、重复事件及积压 |
| 可暂停任务与继续关系 | 等待后保留本次计算的进度 | 调度、公平性、失败、取消及资源归属 |
| 组件更新与提交边界 | 把计算与可观察界面更新关联 | 可重算性、副作用和结果发布时机 |
| 分层队列或检查点 | 区分不同工作的顺序及更新边界 | 饥饿、重入、无限连锁更新及跨队列顺序 |
宏任务/微任务只是一种组织顺序的具体办法。Endorphin 是否需要类似机制,应由事件处理、继续计算和结果呈现之间的顺序要求决定。固定阶段与依赖驱动的更新也可以服务不同实体,不需要先把所有对象放入一个通用循环。
远程数据同步可用于检查跨端身份、变化到达和更新顺序;它只是验证场景之一。执行模型的主问题仍是:入口怎样建立活动,执行如何推进,等待怎样保存并继续,以及活动由谁结束。
[12 门语言的执行模型与生命周期](language-runtime-lifecycles.md) · [关键词手册](language-keywords.md) · [返回目录](../README.md)
+17 -3
View File
@@ -12,25 +12,39 @@
| r/w/x | 读取、编辑资源与使用程序的操作类别;业务写入不自动要求调用者拥有编辑权 | [操作分工](../guide/02-user-identity.md#26-rwx-的操作分工) |
| workspace 角色 | 在 workspace 范围授予常用权限组合与管理能力的成员角色 | [Workspace 角色与授权](../guide/02-user-identity.md#27-workspace-角色与授权) |
| 代码可视域 | 声明可在什么程序位置被引用的范围,区别于平台用户权限 | [平台权限与代码可视域](../guide/02-user-identity.md#29-平台权限与代码可视域) |
| namespace | 资源归属、组织与检索的单位;代码资源形成可见代码视图 | [namespace](../guide/03-namespaces.md) |
| namespace | workspace 内部的命名、组织与检索单位;成员入口指向资源 ID | [namespace](../guide/03-namespaces.md) |
| namespace key | workspace handle 与非空 namespace 路径组成的定位标识 | [namespace](../guide/03-namespaces.md) |
| 代码段 | 独立存储、具有明确归属的代码内容单位 | [代码存储与视图](code-storage-and-views.md) |
| 可见代码视图 | 由索引成员关系获得的 namespace 逻辑代码集合 | [代码存储与视图](code-storage-and-views.md) |
| use | 引用完整 namespace key 的声明 | [程序结构与导入](../guide/04-program-structure.md) |
| Preflight | 定义准备与检查阶段;定义生命周期覆盖创建、准备、持续可引用、更新与退出 | [Preflight 与 inflight](../guide/05-preflight-and-inflight.md) |
| inflight | 实际执行阶段;运行时生命周期覆盖调用、实例、任务及保存的运行状态 | [Preflight 与 inflight](../guide/05-preflight-and-inflight.md) |
| REPL | 持续接收输入、检查并求值、呈现结果的交互式会话;Endorphin 的会话及控制行为为设计提案 | [交互式会话(REPL)](../guide/14-repl.md) |
| 基础常量资源 | 数值、文本、媒体和 GIS 等不可原地修改的基础内容 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
| 统一数值 | 不按整数位宽或浮点编码分型的数值类别;本文暂用 Number 命名 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
| 格式归一化 | 接受的媒体和 GIS 格式导入后转写为内部标准格式,导出时再编码 | [资源、类型与类](../guide/07-types-and-classes.md#71-类型标注) |
| 类型 | 描述资源或值的结构及其允许用法的定义 | [资源、类型与类](../guide/07-types-and-classes.md) |
| Object | 没有父类型的继承根;自身是 Type 的实例,平台按具体类型管理对象生命周期 | [Object](../guide/07-top-level-types/README.md#object) |
| 平台对象 | 由平台识别、管理和存储的对象;描述已有 Object 模型的管理方式,不另设基础类型 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
| 本地副本 | 执行端为远程对象准备的类型化本地表示,保存已取得的数据及目标身份关联 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
| 同步关联 | 将对象后续变化通过网络传递到本地副本的持续关系,不保证多端瞬时一致 | [跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步) |
| Type | 类型对象的实例类型;自身也是 Type 的实例,并继承 Object | [Type](../guide/07-top-level-types/definitions.md#type) |
| 实例化线 | 对象与其直接实例类型的关系,以 x ∈ T 表示;类型自身也是对象 | [实例化线](../guide/07-top-level-types/README.md#实例化线) |
| 继承线 | 子类型与父类型的关系,以 A ⊆ B 表示,区别于对象的实例类型关系 | [继承线](../guide/07-top-level-types/README.md#继承线) |
| atom | 对象可独立识别、保存和引用的资源单元,允许由其他对象组合而成 | [Object、atom 与资源 ID](../guide/07-top-level-types/README.md#objectatom-与资源-id) |
| 类型系统 | 在 Object 基础上约束成员、容器、引用和定义,组织高级结构及能力关系的规则体系 | [Object 与类型系统](../guide/07-top-level-types/README.md) |
| 顶级类型 | 平台原生支持的对象类型;Object 提供共同基础,其他类型规定具体结构及行为 | [Object 与类型系统](../guide/07-top-level-types/README.md) |
| 资源 ID | 独立于 workspace、namespace 命名入口的逻辑资源身份 | [资源引用](../guide/07-top-level-types/references.md) |
| trait | 构造可显式实现与组合的能力定义对象的入口,自身也是对象;Trait 为能力定义的类型候选 | [trait、Trait](../guide/07-top-level-types/definitions.md#traittrait) |
| Function | 平台原生的可调用代码类型,可扩展函数行为和生命周期;具体语法待定 | [Function](../guide/07-top-level-types/functions.md) |
| 类型身份 | 由具体类型声明确定的身份;成员相同不自动使不同声明兼容 | [类型身份与兼容](../guide/07-types-and-classes.md#76-类型身份与兼容) |
| class | 组织数据结构、字段和成员函数的声明 | [资源、类型与类](../guide/07-types-and-classes.md) |
| class | 构造具有名义身份的类型对象的入口,自身也是对象;构造的类型组织字段与成员函数 | [class](../guide/07-top-level-types/definitions.md#class) |
| 表达式 | 描述计算并产生值的源码形式 | [表达式与绑定](../guide/08-expressions-and-bindings.md) |
| 绑定 | 将表达式结果关联到局部名称 | [表达式与绑定](../guide/08-expressions-and-bindings.md) |
| 变量 | 可改变目标的资源引用;具体声明和赋值形式待定 | [变量与资源引用](../guide/08-expressions-and-bindings.md#86-变量与资源引用) |
| 函数 | 定义输入、结果和执行逻辑的可调用声明 | [函数与调用](../guide/09-functions-and-calls.md) |
| 数据依赖 | 后续计算需要前一计算结果的关系 | [函数与调用](../guide/09-functions-and-calls.md) |
| agent | 复用共有成员并建立模型驱动执行与状态关联的语言资源声明 | [Agent](../guide/13-agents.md) |
| Agent、agent | Agent 为运行对象类型;agent 为具体类型对象的构造入口,二者都属于对象体系 | [Agent](../guide/13-agents.md) |
| tool | 关联为模型可选能力的函数,可以是外部引用或内部成员函数 | [Tools 与逻辑实现](../guide/13-agents.md#133-tools-与逻辑实现) |
| memory | 信息保留与恢复的职责,包含会话记忆、检查点和长期记忆 | [Memory 与保存恢复](../guide/13-agents.md#134-memory-与保存恢复) |
| state | 当前业务及执行状态,可用于有限状态机与条件路由 | [State、有限状态机与路由](../guide/13-agents.md#135-state有限状态机与路由) |
File diff suppressed because it is too large Load Diff
+384
View File
@@ -0,0 +1,384 @@
# 12 门语言的执行模型与生命周期
本文比较代码如何进入执行、运行状态如何保存、等待后如何继续,以及资源如何结束存续。逐词含义见[关键词手册](language-keywords.md);请求、场景和界面的完整路径见[框架如何接管代码执行](framework-runtime-lifecycles.md)。本文是外部语言参考,不定义 Endorphin 的新语法或默认调度规则。
执行模型资料核对日期:2026-10-13。关键词版本基线沿用原手册;这里分析指定实现的机制,不宣称覆盖所有实现或版本。Python 使用 CPython 3.14;Java 使用 Java SE 26 的规范;C 使用 C23 公开草案;C++ 使用公开工作草案的相关条款,不将其所有新增能力归入 C++23。Go runtime、React 源码和其他持续更新的官方资料,只作为所注明实现的证据。Kotlin 已发布规范中的协程说明用于解释机制,不作为 Kotlin 2.4 全量版本审计;Julia 使用官方 v1 文档,不将实现细节冻结为 1.11 的全部承诺。
## 阅读路径
先阅读统一模板,再选一门熟悉的语言。建立普通调用的认识后,比较协程和任务,最后进入框架案例。
| 语言 | 分析入口 | 框架或宿主案例 |
| --- | --- | --- |
| Python | [CPython、执行帧与协程](#1-python) | [FastAPI](framework-runtime-lifecycles.md#路径二fastapi) |
| JavaScript | [执行上下文、Promise 与宿主](#2-javascript) | [Node/Chromium](framework-runtime-lifecycles.md#node-与-chromium)、[React](framework-runtime-lifecycles.md#路径五react) |
| TypeScript | [类型处理与 JavaScript 执行](#3-typescript) | [TSX 与 React](framework-runtime-lifecycles.md#路径五react) |
| Java | [JVM、类初始化与线程](#4-java) | [Spring Boot](framework-runtime-lifecycles.md#路径三spring-boot) |
| C | [进程入口与存储期](#5-c) | [普通进程](framework-runtime-lifecycles.md#路径一c-普通进程) |
| C++ | [对象生命周期与协程帧](#6-c) | 库或宿主提供调度 |
| C# | [.NET、Task 与状态机](#7-c) | [Unity](framework-runtime-lifecycles.md#路径四unity) |
| Go | [goroutine、channel 与 runtime](#8-go) | runtime 调度 |
| Rust | [所有权、Future 与 executor](#9-rust) | 异步运行库提供调度 |
| Swift | [ARC、Task 与 executor](#10-swift) | 并发运行时及应用宿主 |
| Kotlin | [Continuation、Job 与 dispatcher](#11-kotlin) | 协程库及目标平台 |
| Julia | [方法、Task 与调度](#12-julia) | Julia 运行时 |
## 统一分析模板
### 常用结构名称
| 名称 | 本文中的含义 |
| --- | --- |
| frame/执行帧 | 一次调用或执行的参数、局部状态与继续关系;具体布局由实现决定 |
| continuation/继续关系 | 暂停后该怎样继续计算,可以用保存状态、函数或其他结构表达 |
| 状态机 | 将执行进度表示为不同状态及迁移,并保存跨暂停需要的数据 |
| scheduler/executor | 接收工作并安排推进的设施;不等于所有计算都由它解释执行 |
| awaiter/等待协议 | 检查是否完成,并在需要等待时建立继续关系的机制 |
| Task/Job | 具体运行环境管理的活动或工作;同名设施在不同语言中并不等价 |
| Future/Promise | 表达结果及其后续取得或推进协议的设施;不等于专属线程 |
| GC/ARC/RAII | 分别强调可达性回收、引用计数管理、将资源管理关联到对象初始化与析构;具体保证见各语言 |
| JIT/AOT | 分别表示运行时编译与提前编译;它们回答代码怎样准备,不直接定义哪个业务事件触发调用 |
### 生命周期属于一个具体实体
“程序的生命周期”通常包含多个不同尺度的生命周期。进程仍然存在时,函数调用可以已经返回;组件仍然存在时,某次渲染可以已经完成;任务暂停时,其上下文仍然存在。分析时先明确实体,再讨论状态。
| 实体 | 典型开始 | 典型结束 | 不能混淆的关系 |
| --- | --- | --- | --- |
| 进程或应用 | 启动入口被接管 | 正常退出、关闭或终止 | 应用存续不意味着用户代码持续执行 |
| REPL 会话 | 创建输入与求值上下文 | 会话关闭 | 一次输入完成后,绑定仍可保留 |
| 函数定义 | 定义被创建、加载或准备 | 不再需要或所属环境结束 | 定义存在不意味着函数体已经执行 |
| 一次调用 | 控制流进入函数 | 返回或异常离开 | 同一函数可以对应很多次独立调用 |
| 协程或任务 | 创建状态及进入执行 | 完成、失败或取消处理结束 | 创建、调度、首次运行可能是不同动作 |
| 组件或订阅 | 挂载、启用或注册 | 卸载、禁用或取消订阅 | 一次回调返回通常不销毁组件或订阅 |
| 数据对象或资源 | 构造、分配或获得资源 | 释放、销毁或回收 | 内存回收与文件、连接关闭分别处理 |
### 定义、上下文、管理结构分别保存信息
下面是比较用的概念分类,不要求每个实现都存在三个同名结构。
| 结构组 | 保存的信息 | 常见实例 |
| --- | --- | --- |
| 代码与定义 | 可执行逻辑、类型、模块、依赖及捕获环境 | code object、函数对象、方法元数据、机器码、模块记录 |
| 一次执行的上下文 | 输入、局部绑定、进度、等待及结果关系 | 栈帧、协程帧、Continuation、goroutine 栈 |
| 调度与管理结构 | 就绪工作、等待者、触发关联及所有者 | 就绪队列、I/O 注册表、Task、Job、组件树、订阅表 |
执行上下文需要能够支持下列职责,但信息可以分散保存、被编译器消除,或由外部宿主提供。
| 信息 | 作用 | 典型承载方式 |
| --- | --- | --- |
| 本次采用的代码与依赖 | 确定执行哪份逻辑 | 方法元数据、函数引用、代码地址与环境 |
| 输入与局部绑定 | 保存这次计算的数据 | 局部槽位、寄存器、栈、状态机字段 |
| 当前进度 | 决定继续执行的位置 | 指令位置、返回地址、状态机标签 |
| 执行状态 | 区分运行、等待和结束 | Task/Job 状态、调度器记录 |
| 等待条件与继续位置 | 外部条件满足后能够继续 | awaiter、Waker、等待队列、Continuation |
| 调用关系与结果接收者 | 交付返回值或失败 | 调用栈、Promise reaction、父任务、回调 |
| 执行身份与可用能力 | 判断操作的归属与授权 | 进程权限、请求上下文、宿主能力;不是所有语言执行帧的原生字段 |
对象地址只在所在进程的地址空间里有意义。网络发送的是协议表示;接收端创建或更新自己的对象。跨端关联必须另有身份和通信约定,不能从局部变量名字推断远端内存位置。Endorphin 对平台对象的说明见[资源访问与呈现](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步)。
### 触发、调度与执行承担不同职责
触发关系确定发生某个条件后应进入哪段逻辑。调度确定工作何时获得执行机会。执行引擎或原生代码推进具体计算。普通同步调用可以直接进入函数,不经过应用任务队列;应用事件循环之外,还可能有操作系统线程调度。
```mermaid
flowchart LR
A[启动、输入、事件或条件满足] --> B[确定入口与输入]
B --> C[直接调用或提交可运行工作]
C --> D[执行引擎或原生代码推进]
D --> E{本次执行的结果}
E --> F[返回或失败:交付结果并清理]
E --> G[等待:保存上下文与等待关系]
G --> H[条件满足:重新获得执行机会]
H --> D
```
图中是概念路径,不能据此推出统一队列、抢占策略或状态枚举。回调注册通常保存关联,注册函数自身也可能执行初始化逻辑;必须查具体 API。等待结果的任务也不一定需要不断主动轮询。
比较可暂停活动时,可以使用下面的分析状态;它们不是各语言共有的原生枚举。
| 分析状态 | 进入条件 | 后续处理 |
| --- | --- | --- |
| 已创建 | 逻辑与初始上下文已经关联 | 可能尚未调度或运行,例如新建的 Julia Task |
| 可运行 | 有条件推进,但尚未获得执行机会 | 由相应调度策略选中 |
| 运行中 | 正在推进代码 | 继续、等待、完成或失败 |
| 等待中 | 当前不能继续,已保存状态及等待关系 | 条件满足后获得继续机会 |
| 已完成/失败 | 逻辑得到结果或以错误结束 | 交付结果,完成相应清理;结果句柄仍可存续 |
取消请求可以在运行或等待期间出现;活动接受取消、执行清理并终止之前,不能把“请求取消”直接当成“已结束”。组件的启用、提交或卸载也不是上表的同一套状态。
### 恢复、重算、释放各有含义
恢复是在保留的上下文中继续;重算是开始另一次求值。React 再次调用组件属于重新计算,Rust executor 再次 poll 同一个 Future 属于推进保存的状态。取消通常是请求停止及处理清理,不自动撤销已经发生的写入。GC 判断内存对象是否可回收,不代替所有业务资源的关闭。
## 1. Python
**入口与执行者。** CPython 执行脚本、模块或 REPL 输入中的代码块。模块顶层会执行;执行 `def` 创建函数并处理默认值、装饰器等,普通函数体在调用时运行。`class` 的类体在定义类时执行。首次导入通常执行模块初始化,后续导入通常使用模块缓存。Python 规范中的执行帧概念与 CPython 具体实现应分开。[Python 执行模型](https://docs.python.org/3.14/reference/executionmodel.html)、[复合语句](https://docs.python.org/3.14/reference/compound_stmts.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| code object | 编译后的代码及常量、名称等元数据 | 可被函数引用和多次执行;不包含某次调用的全部数据 |
| function object | code、全局环境、默认值、闭包等 | 定义执行时创建,通常跨多次调用存续 |
| 执行帧及解释器内部状态 | 局部绑定、进度、调用关系 | 一次执行;可因生成器、协程或外部引用保留 |
| coroutine/generator、asyncio Task | 可暂停状态;Task 进一步跟踪结果、取消和调度 | 调用者或事件循环持有,完成不等于引用立即消失 |
| PyObject 及具体对象结构 | CPython 对象的类型及具体内容 | 对象存续期间;不是“当前正在执行”的标记 |
`PyObject` 是 CPython 对象表示的基础,不是在每次运行字节码时才统一创建。启动初始化、执行定义、构造值都可能产生对象;code、function 与一次执行的帧也不同。[对象 C API 说明](https://docs.python.org/3.14/c-api/intro.html#objects-types-and-reference-counts)、[函数对象 C API](https://docs.python.org/3.14/c-api/function.html)、[代码对象 C API](https://docs.python.org/3.14/c-api/code.html)
具体帧内部表示不等于每次调用立即创建一个可见 `PyFrameObject`。CPython 的帧优化允许在需要时才物化相应 Python 帧对象;不能用调试器看见的对象反推每次调用的全部分配行为。[按需创建 Python 帧](https://docs.python.org/3.14/whatsnew/3.11.html#cheaper-lazy-python-frames)
**进入与等待。** 普通函数调用立即进入函数体;生成器调用先取得生成器,迭代推进它。调用 `async def` 先得到 coroutine,随后由 `await`、`asyncio.run` 或 Task 等方式驱动。Task 的急切执行配置会改变首次推进时机,不能一律理解为下一轮循环才开始。[asyncio 协程与任务](https://docs.python.org/3.14/library/asyncio-task.html)
下面是 CPython/asyncio 的独立示例,预期输出顺序为 `created`、`body`、`42`,不是运行日志。
```python
import asyncio
async def price():
print("body")
await asyncio.sleep(0)
return 42
async def main():
pending = price()
print("created")
print(await pending)
asyncio.run(main())
```
**结束与关键词。** `return` 和异常结束调用;`yield` 保存生成器继续状态,`await` 表达等待。`with`、`finally` 用于资源退出处理;`del` 删除绑定等,不保证对象立即销毁。CPython 的引用计数及循环 GC 是实现机制,不是所有 Python 实现必须照搬的机制。[Python 数据模型](https://docs.python.org/3.14/reference/datamodel.html)。请求入口另由 [FastAPI 与 ASGI](framework-runtime-lifecycles.md#路径二fastapi)组织。
## 2. JavaScript
**入口与执行者。** 宿主启动脚本或模块求值,再通过普通调用和回调进入函数。V8 是 Node 与 Chromium 使用的执行引擎;网络、DOM、定时器和完整宿主事件循环分别由宿主提供。ECMAScript 定义执行上下文与环境记录,它们是规范模型,不要求 V8 使用相同名称或布局。[ECMAScript 执行上下文](https://tc39.es/ecma262/2026/multipage/executable-code-and-execution-contexts.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 函数、脚本/模块及环境 | 逻辑、绑定和闭包捕获 | 引擎管理;模块求值与函数调用分别发生 |
| 执行上下文栈 | 当前函数、环境及执行进度 | 活跃的同步调用;闭包环境可继续存续 |
| Promise 与 reaction | 完成状态、结果及后续处理 | Promise 解决后仍可被引用,不等于线程或整个执行帧 |
| 生成器/异步继续状态 | 暂停后的局部信息与继续关系 | 引擎保存并按相应协议恢复 |
| 宿主任务与微任务管理 | 可运行的回调或 job | 队列、检查点和执行时机受宿主规范约束 |
**进入与等待。** 普通函数立即运行;`async` 函数调用会运行同步前缀,再返回 Promise,`await` 后续通过异步继续机制推进;生成器由 `next()` 等驱动。Promise 构造器的 executor 与 `.then()` 注册的后续处理不是同一个时机。[ECMAScript 函数定义](https://tc39.es/ecma262/2026/multipage/ecmascript-language-functions-and-classes.html)、[Promise 对象](https://tc39.es/ecma262/2026/multipage/control-abstraction-objects.html#sec-promise-objects)
下面是普通脚本示例,预期输出 `start`、`outside`、`resume`。
```javascript
async function price() {
console.log("start");
await Promise.resolve();
console.log("resume");
}
price();
console.log("outside");
```
**调度与结束。** 浏览器在规定位置执行微任务检查点,清空过程中还可加入新微任务;渲染发生在符合条件的渲染机会,不保证每个任务后立即绘制。Node 另有 libuv 阶段和 `process.nextTick` 规则。`return`、`throw`、`try/finally` 描述调用及清理,GC 不能代替解除事件监听或业务资源关闭。[HTML 事件循环](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)、[Node 事件循环](https://nodejs.org/learn/asynchronous-work/event-loop-timers-and-nexttick)
## 3. TypeScript
**入口与执行者。** 通常由工具处理 TypeScript,输出或交给后续工具产生 JavaScript,再由所选宿主执行。类型检查不是持续坐在 JavaScript 和 V8 之间的另一台解释器。`type`、`interface` 等类型信息通常被擦除;部分构造如普通 `enum`、`namespace` 可以生成运行时代码,不能把所有 TS 内容都理解为无运行效果。[类型擦除](https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types)、[枚举](https://www.typescriptlang.org/docs/handbook/enums.html)、[namespace](https://www.typescriptlang.org/docs/handbook/namespaces.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 编译工具的 AST、符号与类型信息 | 源码关系、类型检查及转换所需信息 | 构建或编辑会话;通常不进入应用运行堆 |
| 生成的 JS 模块、函数和对象 | 真正运行的逻辑与数据 | 采用 JavaScript 的运行模型 |
| source map | 源码与生成代码位置的对应 | 调试工具使用;不负责调度 |
| 框架自己的组件、任务或请求记录 | React、服务端等管理状态 | 由对应框架承担,不是 TypeScript 类型对象 |
**调用与等待。** `async`、`await` 的可观察调用行为依照目标 JavaScript 及工具生成的支持代码。TS 的返回类型 `Promise<number>` 描述结果契约,不因类型标注自行启动任务。值导入可能带来模块初始化;纯类型导入不为类型本身创建业务运行对象。
**TSX 与结束。** JSX 可以由 TypeScript 转换,也可以保留给其他工具处理;生成代码调用 React 等库,然后才进入组件管理。清理、事件循环和对象回收归实际宿主与库。完整路径见 [React 构建、浏览器执行及 SSR](framework-runtime-lifecycles.md#路径五react)。[TypeScript JSX 模式](https://www.typescriptlang.org/docs/handbook/jsx.html)
## 4. Java
**入口与执行者。** 启动器选择入口,JVM 完成必要的类加载、链接、初始化并调用入口方法。示例可采用传统 `static main(String[])`,但不能把 Java SE 26 的所有入口都限定为这个签名。类初始化与实例构造也不同;`import` 是名称使用规则,不是每次运行到一行就远程加载并执行一个类。[Java 启动与初始化](https://docs.oracle.com/javase/specs/jls/se26/html/jls-12.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 类元数据、方法及运行时常量池 | 已加载定义与方法逻辑 | JVM/类加载器管理 |
| 每线程的 JVM 栈与 frame | 局部变量、操作数栈及调用关联 | 一次方法调用建立 frame,正常或异常离开时结束 |
| 堆中的实例 | 字段与对象关系 | 可越过调用边界,由 GC 管理可达性 |
| Thread、执行器及 Future 类设施 | 线程活动、待提交工作和结果 | 标准库及宿主策略;不要求统一事件循环 |
JVM 规范区分共享堆与每线程状态,但不规定所有实现的 GC、JIT 或物理内存布局。解释执行、编译后的机器码执行都可实现相同方法语义。[JVM 运行时数据区与 frame](https://docs.oracle.com/javase/specs/jvms/se26/html/jvms-2.html)
**开始与等待。** 普通方法调用直接进入;`Thread.start()` 启动线程执行其逻辑,而直接调用 `run()` 仍是普通方法调用。平台线程、虚拟线程、执行器及异步结果设施各有管理契约。阻塞当前线程不是“Java 必须有一个浏览器式微任务队列”。[Thread API](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/lang/Thread.html)
**结束与关键词。** `return`、`throw` 结束调用,`finally` 和带资源的 `try` 处理退出;对象可达性与外部资源关闭分别判断。`synchronized` 影响互斥和内存可见性,不负责启动应用请求。Spring 中的 bean 和请求生命周期见 [Spring Boot 案例](framework-runtime-lifecycles.md#路径三spring-boot)。
## 5. C
**入口与执行者。** 在 hosted 环境中,启动流程完成必要准备后进入 `main`;freestanding 环境的启动由实现规定。常见原生实现将函数编译为机器码,由操作系统启动进程、调度线程,CPU 执行指令。C 规范不要求应用事件循环,也不规定一定有某种物理栈布局。[C23 公开草案 N3096,5.1.2、6.2.4](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 可执行代码、全局及静态对象 | 函数逻辑和长期状态 | 加载与启动流程;静态存储期贯穿程序执行 |
| ABI 约定下的寄存器与栈等 | 参数、局部状态和返回位置 | 常见实现的一次调用;内联可消除独立栈帧 |
| 分配存储区及指针 | 动态数据与访问地址 | `malloc`/`free` 等接口管理;C 不提供默认 GC |
| 库自建的回调表、队列或线程记录 | 外部事件与执行关联 | 由库或宿主定义,不能从 C 关键词推出 |
**调用与等待。** 执行调用表达式进入函数,再返回调用位置。保存函数指针不会自动运行函数。同步 I/O 可能阻塞线程;非阻塞 I/O 与事件循环需要操作系统和库的接口。`while` 可以写调度循环,也可以只是计算循环,两者用途不同。
**结束与关键词。** 自动存储期、静态存储期和分配存储期不同;离开函数不自动释放所有动态内存。`static`、`_Thread_local` 等影响存储属性,`return` 结束函数;`free`、`atexit` 是库名称。正常退出和强制终止的清理保证不同。完整入口例子见[普通进程路径](framework-runtime-lifecycles.md#路径一c-普通进程)。
## 6. C++
**入口与执行者。** 普通原生程序经启动及初始化进入 `main`,函数通过调用表达式执行。与 C 相比,C++ 特别区分存储的取得、对象生命周期开始、析构和存储释放;这些步骤不能只合称“对象在内存里”。[启动](https://eel.is/c++draft/basic.start)、[对象生命周期](https://eel.is/c++draft/basic.life)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 编译后的函数与类型相关信息 | 调用逻辑、布局及所需分派信息 | 编译实现管理,不要求所有类型都有运行时对象 |
| 普通调用状态与自动对象 | 参数、局部数据和退出时析构关系 | 正常离开及适用的异常展开触发析构 |
| 所有权容器与动态对象 | 指针及释放责任 | 如 RAII 包装器;原始指针本身不自动表达所有权 |
| coroutine state、promise 与 awaiter | 参数、跨暂停局部状态及继续协议 | 编译器与库共同管理,最终需要适当销毁协程状态 |
**进入与等待。** `co_await`、`co_yield`、`co_return` 参与协程协议。首次是否暂停由 promise 的 `initial_suspend` 等决定;等待是否真暂停由 awaiter 决定。C++ 不因为出现 `co_await` 就自带统一 scheduler 或创建线程。这里的 promise 是协程协议对象,不能直接等同于 JavaScript Promise。[协程定义](https://eel.is/c++draft/dcl.fct.def.coroutine)
**结束与关键词。** RAII 把资源退出关联到对象析构,`try/throw` 的异常展开可触发清理;异常终止等情形不能套用普通展开保证。协程逻辑完成后还可能停在最终暂停点,完成和 frame 释放不同;裸 handle 的遗失不自动等于安全销毁。`delete`、析构及所有权包装器负责相应存续,`constexpr` 等编译期能力不属于宿主事件调度。[析构函数](https://eel.is/c++draft/class.dtor)
典型协程轨迹:调用建立状态 → 按 initial_suspend 协议继续或暂停 → awaiter 检查与继续 → 逻辑完成 → 最终暂停及状态销毁按各自协议处理。scheduler 是库或宿主角色,不由协程关键词单独决定。
## 7. C#
**入口与执行者。** 以常见 .NET 应用为基线,编译产生程序集中的 CIL 和元数据,运行时通过 JIT 等路径执行;AOT 是另一种路径。入口可由 `Main` 或顶层语句等构成。CLR 管理执行与内存,不自动为所有应用规定 Unity 的帧循环。[托管执行过程](https://learn.microsoft.com/en-us/dotnet/standard/managed-execution-process)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 程序集、类型和方法元数据 | 可执行定义及类型关系 | 加载及运行环境管理 |
| 普通方法调用状态 | 参数、局部状态和返回关系 | 调用进入至返回或异常离开 |
| 编译器生成的 async 状态机 | 跨暂停局部状态、当前位置和 awaiter | 一次异步调用;具体表示可优化 |
| Task 与继续处理 | 完成状态、结果、异常等 | 可被多方等待;不等于一个专属线程 |
| SynchronizationContext/TaskScheduler 等 | 继续工作的执行策略 | 库、宿主和调用配置共同决定 |
**开始与等待。** 普通 `async Task` 方法被调用时会先同步推进;遇到尚未完成的 awaitable 才需要暂停。awaitable 已完成时可以继续同步推进,不能照抄 JavaScript `await` 的时间模型。继续位置保存在状态机中,恢复线程由捕获的上下文等规则影响,不保证总在原线程。[Task 异步模型](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model)
**结束与关键词。** `return` 或异常使 Task 得到相应结果;取消是合作处理,不是自动回滚。`using`/`await using` 关联资源释放,`lock` 关联互斥,GC 管理内存可达性。Task 完成、资源 Dispose、对象回收是不同事件。[GC 基础](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals)
Unity 是另一种宿主组合,具有 Mono/IL2CPP 后端及 PlayerLoop;其 `IEnumerator` 协程由引擎推进,不等于 C# async Task。[Unity 案例](framework-runtime-lifecycles.md#路径四unity)
## 8. Go
**入口与执行者。** 包变量初始化、`init` 函数及 `main.main` 有规定的启动关系。普通函数调用由当前 goroutine 执行;`go f(args)` 先在调用方求值函数及参数,再让新 goroutine 执行调用。Go 自带 runtime 管理 goroutine,不需要每个应用先自己编写事件循环。[Go 程序初始化与执行](https://go.dev/ref/spec#Program_initialization_and_execution)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 包、编译代码与初始化状态 | 定义、全局数据及启动顺序 | 程序初始化和运行 |
| goroutine 的栈及 g 记录 | 调用链、保存的执行状态及调度状态 | runtime 管理一次 goroutine 活动 |
| M 与 P | OS 线程、执行 Go 代码所需的运行时资源 | 当前 runtime 的 G/M/P 实现模型 |
| channel 与等待关系 | 缓冲、通信状态和发送/接收等待者 | 程序引用与 runtime 共同维持 |
| 堆对象 | 跨调用、跨 goroutine 的数据 | GC 跟踪可达性;不保证每个局部值都进堆 |
G/M/P 是具体 Go runtime 的实现说明;P 是调度资源,和用户权限没有关系。goroutine 不要求绑定一个永远专属的 OS 线程。[Go runtime HACKING](https://go.dev/src/runtime/HACKING)、[Go GC 指南](https://go.dev/doc/gc-guide)
**等待、结束与关键词。** channel 操作、`select` 等可让 goroutine 等待,runtime 保存状态并在条件合适时安排继续。`defer` 在外围函数退出时处理延后工作,不在每次等待时触发。`main` 返回会结束程序,不等待所有其他 goroutine 自行完成;应用需要明确等待和关闭安排。关闭 channel 表达通信协议,不等于强制杀死全部相关 goroutine。
典型轨迹:包初始化 → main → `go` 启动活动 → runtime 安排推进 → channel 条件不满足时等待 → 条件满足后继续 → 函数退出并执行 defer。main 是否仍在等待其他工作,由应用的同步逻辑决定。
## 9. Rust
**入口与执行者。** 普通原生程序从入口进入函数调用。所有权、借用与生命周期注解约束值的使用;生命周期注解通常是编译期关系,不是运行时事件回调。默认内存管理依赖所有权及 Drop,不要求跟踪式 GC。[所有权](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 编译后的函数与类型表示 | 调用逻辑和数据布局 | 编译器及链接环境管理 |
| 普通调用状态与所有权值 | 参数、局部值及退出释放责任 | 作用域及移动后的所有者决定存续 |
| async 生成的 Future 状态 | 跨等待局部数据和进度 | Future 的所有者持有;由 poll 推进 |
| Context/Waker | 通知 executor 某项工作应再获推进机会 | Future 与 executor 的恢复协议 |
| executor 的 task 与队列 | Future、调度状态及唤醒关联 | 所选异步运行库定义;标准语言不指定唯一 executor |
**进入与等待。** 调用 `async fn` 创建 Future,函数体在 Future 被推进时执行。`.await` 不自动创建独立并发任务;spawn 由运行库提供。`poll` 返回 `Pending` 或 `Ready`;Waker 通知需要再安排推进,不保证被唤醒就已经有最终结果,也不要求无限忙等。某些 Future 是已启动活动的结果句柄,不能从“Future 惰性推进”推断背后所有工作都尚未开始。[async 函数](https://doc.rust-lang.org/reference/items/functions.html#async-functions)、[Future 协议](https://doc.rust-lang.org/std/future/trait.Future.html)
**结束与关键词。** 正常作用域退出释放相应拥有的值;panic 的 unwind 与 abort 对析构的保证不同。丢弃 Future 通常停止进一步推进并释放它拥有的状态,但不能撤销已发出的远端操作。`move` 改变捕获方式,`async/await` 参与状态保存与推进,`loop` 本身不构成完整 executor。
典型轨迹:创建 Future → poll → Pending 时保存等待关系 → Waker 通知再调度 → 再次 poll 推进保存的状态 → Ready 交付结果。Future 结束后的内存与资源释放,还取决于所有者。
## 10. Swift
**入口与执行者。** 普通调用与应用入口由 Swift 编译代码及宿主启动;UI 应用还要服从应用框架。调用 async 函数不等于必然创建新的独立 Task。`await` 标记潜在暂停点,不保证每次遇到它都实际暂停。[Swift 官方语言书:并发](https://raw.githubusercontent.com/swiftlang/swift-book/main/TSPL.docc/LanguageGuide/Concurrency.md)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| 编译代码与类型信息 | 函数逻辑和类型关系 | 编译工具及运行环境管理 |
| 普通调用及 async 继续状态 | 参数、局部状态和暂停后进度 | 当前调用与任务活动期间 |
| Task、任务组和取消状态 | 并发活动、结果及父子管理关系 | 结构化并发作用域或非结构化任务安排 |
| actor/executor 管理 | 隔离及工作执行约束 | 并发运行时;actor 不等于专属线程 |
| ARC 管理的类实例 | 强、弱、无主引用及实例数据 | 引用关系决定存续;需要处理强引用环 |
**调度与恢复。** `async let`、任务组和 `Task` 等表达不同任务组织方式。潜在暂停允许其他工作推进,恢复后不能一般性假定 OS 线程不变。actor 保证相应隔离边界,跨 `await` 仍要考虑其他工作可能改变状态。executor 接收并安排可运行的 job,任务可以跨多个这样的执行片段存续。[Swift SE-0304 的 task、job 与 executor 模型](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0304-structured-concurrency.md#executors)
**结束与关键词。** 结构化子任务受外围作用域约束;取消是合作机制。`defer` 关联作用域退出,`deinit` 关联类实例销毁,`weak`/`unowned` 影响引用关系。ARC 主要解释类实例的内存管理,不应套用为所有值都对应独立引用计数堆对象。[Swift 官方语言书:ARC](https://raw.githubusercontent.com/swiftlang/swift-book/main/TSPL.docc/LanguageGuide/AutomaticReferenceCounting.md)
典型轨迹:建立任务作用域 → 调用 async 函数 → 潜在暂停点实际需要等待 → 保存继续状态 → 获得 executor 的继续机会 → 返回结果及完成作用域清理。任务存续跨越暂停,不是每次恢复都创建一份全新业务计算。
## 11. Kotlin
**入口与执行者。** 本节以 Kotlin/JVM 为基线:编译结果由 JVM 执行,普通函数有 JVM 调用状态。Kotlin/JS 和 Kotlin/Native 使用不同目标环境,不能把 JVM 栈和 GC 推广到所有 Kotlin 程序。`suspend` 表明函数可以参与可暂停调用,不自行创建一个新协程。[Kotlin 协程规范](https://kotlinlang.org/spec/asynchronous-programming-with-coroutines.html)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| JVM 方法与类元数据 | 编译后的逻辑及定义 | JVM 目标环境管理 |
| Continuation 与状态机 | 结果接收位置、跨暂停局部状态和进度标签 | 可暂停计算的继续关系;不是当前 OS 线程的别名 |
| CoroutineContext | dispatcher、Job 等上下文元素 | 协程库及继承、覆盖规则管理 |
| Job/Deferred | 活动状态、父子关系、取消及结果 | kotlinx.coroutines 的管理对象,不是语言关键词 |
| dispatcher 与等待管理 | 决定工作在哪种执行环境推进 | 所选库和宿主提供 |
**进入与等待。** `launch`、`async` 等 builder 由 kotlinx.coroutines 创建并组织活动;开始时机受启动模式影响。调用 suspend 函数可继续在现有协程中执行,不等于 spawn。编译器可将暂停路径转换为带局部字段及状态标签的继续结构;恢复可能更换线程,也可能依据 dispatcher 保持特定线程约束。[协程上下文与 dispatcher](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html)
**结束与关键词。** Job 完成、子任务结束、取消传播及 `finally` 清理分别遵循协程库与语言规则。JVM 的 GC 管理内存,业务资源仍需合适的关闭协议。`fun`、`suspend`、`try/finally` 分别涉及定义、暂停能力和退出;`Job`、`launch`、`async` 在这里是库设施。
典型轨迹:builder 组织活动及上下文 → 按启动模式进入 → suspend 调用实际暂停时保存状态 → 条件满足后通过 Continuation 恢复 → 返回或异常 → Job 处理完成及子活动关系。继续逻辑和 dispatcher 的执行位置规则共同决定下一步。
## 12. Julia
**入口与执行者。** Julia REPL、脚本及 `include` 可以执行顶层代码。解析、宏展开和 lowering 后,由运行时选择解释或编译等路径处理;函数定义增加方法,不意味着当场执行函数体。调用根据方法分派选择逻辑,运行时可编译相应专门化。[Julia 执行路径](https://docs.julialang.org/en/v1/devdocs/eval/)
| 结构 | 保存什么 | 生命周期及归属 |
| --- | --- | --- |
| Module、方法及专门化相关表示 | 绑定、方法逻辑和可执行代码 | Julia 运行时管理 |
| 普通调用状态 | 参数、局部状态和返回关系 | 一次调用 |
| Task | 可暂停执行状态、结果及活动关系 | 由程序创建、运行时调度 |
| Channel 和等待者 | 通信内容及等待关联 | 任务与 Channel 协议管理 |
| 运行时值表示 | 值、类型及必要的对象头等 | 运行时管理;优化后的值不保证均是单独装箱对象 |
Julia 的 `jl_value_t` 等是实现层的对象表示;它回答值怎样存储,不决定哪个函数什么时候被调度。实现文档的历史细节不能直接充当完整稳定 ABI。[Julia 对象布局](https://docs.julialang.org/en/v1/devdocs/object/)
**进入与等待。** 创建 `Task` 不立即执行其函数体;需要调度或其他推进安排。`@async`、`Threads.@spawn` 等宏会创建并安排任务,但执行位置约束不同。`wait`、Channel 等可以让当前任务等待,运行时安排其他工作;暂停后保留状态,不从函数开头重新运行。[Julia 异步编程](https://docs.julialang.org/en/v1/manual/asynchronous-programming/)
**结束与关键词。** `return` 或异常结束本次调用,`try/finally` 关联退出清理。GC 与外部资源关闭分开处理;`do` 可把函数传给资源管理 API,具体关闭保证取决于被调用的 API。`Task`、`schedule`、`wait`、`Channel` 及这些宏不因为参与生命周期就都变成关键词。
典型轨迹:创建 Task → 调度 → 执行函数体 → wait/通信形成等待 → 条件满足后继续 → 返回或失败,等待者取得相应结果。Task 对象及结果可以在活动结束后继续被引用。
## 横向比较:什么动作真正进入执行
下表只比较所述常见用法。对象创建、提交调度和获得执行机会之间,不能用同一个“启动”掩盖差别。
| 用法 | 这一动作的直接效果 | 下一步由谁推进 |
| --- | --- | --- |
| 各语言的普通同步函数调用 | 当前执行路径进入函数体 | 当前线程/执行引擎继续 |
| Python `async def` 调用 | 创建 coroutine,未执行函数体 | await、Task 等驱动 |
| JavaScript `async` 调用 | 执行同步前缀,返回 Promise | 引擎及宿主协作推进异步继续 |
| C# 常规 `async Task` 调用 | 同步推进,必要时在未完成 awaitable 处暂停 | 状态机、awaiter 与上下文策略 |
| Rust `async fn` 调用 | 创建 Future | await 或 executor 的 poll |
| C++ 协程调用 | 建立协程协议及状态,首次暂停规则由 promise 决定 | 调用者、awaiter 或库的 scheduler |
| Go `go` 语句 | 求值调用信息并启动新的 goroutine | Go runtime 调度 |
| Swift async 调用 | 在当前任务中调用可暂停函数;不必创建新 Task | Swift 并发执行机制 |
| Kotlin suspend 调用 | 在可暂停调用链中执行;不必创建新 Job | Continuation 与协程上下文 |
| Julia `Task` 构造 | 创建任务,未运行函数体 | 调度及运行时推进 |
| React 状态更新 | 请求一次界面更新,不等于直接执行每个 Effect | React 组织渲染与提交,宿主提供执行机会 |
## 生命周期设计的比较结论
以下是基于上面机制的分析归纳,不是任何语言的统一规范。
- **循环不是所有生命周期的必要形式。** C++ 自动对象可以随作用域构造和析构;普通调用可以直接进入并返回。循环适合持续接受工作,但不定义全部存续关系。
- **钩子不是全部调度机制。** 钩子连接条件与逻辑;优先级、执行位置、等待及取消还需要独立规则。命名回调、函数参数、订阅和协程继续位置是不同的连接形式。
- **Task 不等于整个对象体系。** 数据值、代码定义、一次执行、结果句柄和长期组件应分别说明。可以共享基础对象模型,但不能因此共享同一执行状态机。
- **宏任务/微任务是特定宿主的顺序契约。** 是否采用此类分层,应由可观察顺序、更新边界及响应性需求决定,不能从“需要循环”直接推出。
- **长期保存定义不等于长期执行。** 会话、模块、平台对象和订阅都可以存续而暂时没有用户代码运行。
Endorphin 已有的阶段定义见 [Preflight 与 inflight](../guide/05-preflight-and-inflight.md),普通调用见[函数与调用](../guide/09-functions-and-calls.md),会话提案见 [REPL](../guide/14-repl.md)。需要进一步明确的执行契约集中在[框架比较后的设计分析](framework-runtime-lifecycles.md#对-endorphin-执行模型的设计分析)。
[关键词手册](language-keywords.md) · [框架如何接管代码执行](framework-runtime-lifecycles.md) · [返回目录](../README.md)
+90 -15
View File
@@ -7,9 +7,11 @@
| 主题 | 已确定内容 |
| --- | --- |
| 语言定位 | 前后端共用的云原生编程语言,UI 是应用领域之一 |
| 资源归属 | 每项独立登记的资源属于一个 workspace 和至少一级 namespace;用户是操作与作者身份 |
| 资源归属 | workspace 管理归属与协作,namespace 提供命名入口;用户是操作与作者身份 |
| 资源身份 | 独立 ID 识别资源;多个 namespace 可引用同一资源,命名入口变化不改写已保存的确定引用 |
| 资源保留 | 从有效保留根可达的资源不能回收;移除命名入口不等于删除资源,需处理无人使用的循环引用 |
| Workspace 命名 | workspace handle 在平台内唯一并参与 key,workspace 显示名可以重复;用户登录标识不作为资源归属前缀 |
| namespace | 各层语义一致;以外部 key 检索,不在正文声明自身归属;函数、class、agent 和独立保存的基础内容共用资源归属体系 |
| namespace | 各层语义一致;以外部 key 检索,不在源码声明自身归属;函数、class、agent 和独立保存的基础内容共用资源归属体系 |
| key 形式 | `workspace handle:namespace路径`,冒号分隔 workspace 与路径,点号分隔层级 |
| 用户与 workspace | 注册时创建默认个人 workspace,创建用户成为管理员;用户可以参与多个 workspace,workspace 可以包含多个用户 |
| 授权边界 | workspace 整体授权,内部 namespace、class 和函数不各自维护用户访问名单;代码可视域独立处理 |
@@ -26,6 +28,13 @@
| Agent 编程 | agent 可以实现新逻辑并引用已有函数;提交新定义后须经过 Preflight 才能作为已就绪定义执行 |
| 人工在环 | 高风险操作执行前暂停,等待人类确认或修改意见,并保留恢复所需状态 |
| 类型兼容 | 用户声明的类型按声明身份区分,不仅凭字段或方法相同建立兼容或能力实现关系;不采用结构类型兼容 |
| Object 与 Type | Object 是无父类型的继承根;Object 是 Type 的实例,Type 是自己的实例且继承 Object;平台按具体类型管理对象生命周期 |
| 实例化与继承 | 对象的直接实例类型与类型的父类型分别保存和查询;类型对象与运行实例都属于对象体系 |
| 定义构造入口 | class、trait、record、agent 等入口自身也是对象,构造出的类型或定义同样是对象;不预先将入口名称定为保留关键字 |
| Object 与 atom | atom 是对象可独立识别、保存和引用的资源单元,资源 ID 连接对象图;组合对象也可以成为 atom |
| 类型能力 | 在 Object 共同基础上组合多个显式 trait 能力,不要求以一条父子继承链表达全部能力;具体声明规则待定 |
| 类型系统范围 | 基础类型、容器、引用和定义资源共同组织 class、Function、agent 等高级结构;讨论不限于函数签名 |
| Function | 平台原生的函数类型,可扩展行为与生命周期;函数自身类型与调用返回类型分别表达 |
| 调用目标 | 普通逻辑调用表达输入、结果与依赖,系统组织执行 |
| 权限操作分工 | r 读取、w 编辑资源内容或定义、x 使用已定义的程序能力;程序按业务契约产生写入不要求调用者因此成为 Editor;执行不自动授予管理能力 |
| 官方组件 | 官方 UI 组件与用户库内容分别定义 |
@@ -36,20 +45,23 @@
| 资源访问 | 客户端可查看获准访问的资源,依据当前资源或调用结果的类型选择呈现方式 |
| 函数查看与调用 | 必填参数未就绪时查看函数本身;输入满足调用要求后可调用并呈现结果;执行等待不退回为定义查看 |
| 跨端使用 | 函数调用与 hook 关联由平台组织执行和通信,应用直接使用符合声明类型的结果与更新 |
| 跨端对象 | 对象可由平台管理和存储;客户端建立关联同一资源身份的本地副本,通过网络取得数据并同步后续变化;身份关联不表示共享内存或瞬时一致 |
## 收录的语法提案
| 提案 | 正文位置 | 说明 |
| 提案 | 主要说明 | 说明 |
| --- | --- | --- |
| 词法与字面量 | [第 6 章](../guide/06-lexical-structure.md) | 本书统一采用的标识符、字符串、数字和符号形式 |
| 类字段、成员与类型标注 | [第 7 章](../guide/07-types-and-classes.md) | 统一数值暂用 Number,文本沿用 String;类字段与成员函数的具体形式仍为提案 |
| 表达式与 let | [第 8 章](../guide/08-expressions-and-bindings.md) | 基础运算、成员访问与局部绑定 |
| function 与 return | [第 9 章](../guide/09-functions-and-calls.md) | 函数签名、基本函数体与调用组合 |
| function 与 return | [第 9 章](../guide/09-functions-and-calls.md) | 早期基本调用草案;表达具体函数自身类型的替代声明见第 7 章候选 |
| 顶级类型代码示例 | [第 7 章续篇](../guide/07-top-level-types/README.md) | 七组类型逐项展示候选声明、构造、调用与结果;函数声明同时比较两种形式,未合并进正式 EBNF |
| Product.get | [第 10 章](../guide/10-data-access.md) | 读取体验提案,不是 class 自动附带的 API |
| 组件效果 | [第 12 章](../guide/12-ui-components.md) | 参数、布局与默认值的效果提案;构造表达式尚未定义 |
| agent 声明骨架 | [第 13 章](../guide/13-agents.md) | agent 语言地位已确定;共有成员骨架为提案,职责关联形式尚未定义 |
| REPL 会话行为 | [第 14 章](../guide/14-repl.md) | 会话上下文、输入求值、对象查看、执行记录及同步状态的设计提案,不增加已确定的控制命令或顶层文法 |
程序声明组合与[形式文法](formal-grammar.md)同样属于设计稿。正文中的陈述定义这些提案内部的用法,不将其确定程度提升为最终规范。
程序声明组合与[形式文法](formal-grammar.md)同样属于设计稿。语法提案按其内部规则使用,不等于最终规范。
## 身份与权限
@@ -78,7 +90,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 仅具有 x 时的调用接口信息范围,以及程序运行能力与资源编辑权限之间的具体执行机制。
- 角色变更和授权撤销对正在执行、暂停或恢复中的调用、实例与任务的影响。
正文的 atelier、market key 前缀均解释为 workspace handle;alice、bob 仅在成员和作者示意中代表用户。
示例中的 atelier、market key 前缀均为 workspace handle;alice、bob 在成员和作者示意中代表用户。
## 引用与代码视图
@@ -89,7 +101,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 视图顺序、版本选择、成员一致性及编辑操作映射。
- key 的传递编码和索引关联机制。
正文跨 namespace 示例采用目标声明可见、名称可直接解析且无冲突的条件;该条件不代替正式名称查找规则。
跨 namespace 示例采用目标声明可见、名称可直接解析且无冲突的条件;该条件不代替正式名称查找规则。
## 声明与类型
@@ -103,7 +115,30 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 代码更新和不同版本之间的类型身份比较规则。
- 重复声明、完整控制流、实例及字段可变性、赋值和作用域细节。
本文简单函数体仅收录 let 与末尾 return,不意味着整门语言只允许这两种语句。
第 9 章的基本调用草案只展示 let 与末尾 return;第 7 章的类型设计另有赋值、等待等候选示例,两者都不穷尽语言语句。
## 顶级类型讨论
[Object 与类型系统](../guide/07-top-level-types/README.md)定义对象、类型对象及其资源关联。Object/Type 闭环、实例化线与继承线、资源 atom 关系和平台生命周期职责已确定;各类型的完整操作、源码接口与能力接入形式仍分别评审。
| 类型组 | 已确定方向 | 候选与待定范围 |
| --- | --- | --- |
| [Object](../guide/07-top-level-types/README.md#object) | Object ∈ Type、Type ∈ Type、Type ⊆ Object;实例化与继承关联接入资源 ID 图 | 共同操作接口、typeOf 与 basesOf 的具体形式、能力分派、继承语法及登记粒度 |
| [Bool、Number、String、Unit、Null](../guide/07-top-level-types/values.md) | 统一数值、文本与基础常量模型 | Bool、Unit、Null 的地位;基础类型怎样约束结构成员、精度与转换 |
| [Tuple、record、List、Map、Set、Option、Result](../guide/07-top-level-types/collections.md) | 需要组合固定成员、容器和分支结构 | 类型构造与参数规则、名义身份、相等性与可变性;Option 和 Result 为候选 |
| [Ref、Cell](../guide/07-top-level-types/references.md) | 独立资源 ID、确定引用与可变目标引用;按保留根可达性回收 | 显式类型与透明引用的关系、解析时机、保留根和状态引用规则 |
| [Type、Trait、Code、class](../guide/07-top-level-types/definitions.md) | 类型本身是 Type 对象,可传递和引用;代码也是对象;名义类型与多个 trait 能力组合 | 构造入口的具体类型和语法、成员组合、反射和生成规则 |
| [Function](../guide/07-top-level-types/functions.md) | 原生函数类型,可扩展行为和生命周期;自身类型与返回类型分别表达 | 完整声明语法、扩展机制、捕获环境、实例状态与调用生命周期 |
| [Task、Stream、State、Session](../guide/07-top-level-types/execution.md) | inflight 管理运行实体及状态 | 是否独立原生化、内容类型参数,以及等待、取消、恢复和共享规则 |
| [Agent、agent](../guide/07-top-level-types/agents.md) | Agent 是 Type 的实例并继承 Object;具体类型对象与运行实例分别保存 | 具体类型继承 Agent 的形式、构造入口、成员组合及运行生命周期 |
资源 ID 独立于命名入口:workspace 管理归属与协作,namespace 管理组织,同一资源可以具有多个命名入口;移除入口不等于清除仍被保留程序引用的资源。namespace key 中的非空路径要求只描述命名入口,不要求资源始终保留一个入口,也不充当资源 ID 的定义。具体登记及名称绑定机制仍待确定。
atom 是 Object 的资源组织视角,不另外引入 Atom 基础类型。定义对象及实例对象分别保留具体身份与生命周期;运行对象的固定 ID 不冻结其合法状态变化。workspace 与 namespace 的管理职责和资源 atom 分开,不因共同对象模型自动把管理记录变成语言资源。
函数构造必须区分自身类型与调用签名,具体简写尚未确定。trait 组合方向不自动引入 Rust 的其他规则。完整泛型与遗传算法设计尚待定义。
候选示例采用类型参数、箭头签名、显式实现、构造器及任务操作,其状态不构成实现或可执行性保证。
## 基础资源与变量
@@ -128,7 +163,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 定义创建、更新与退出可用范围的接口,以及已有调用或实例对版本的选择。
- 多定义修改的一致性、协作冲突处理和运行中提交代码的可见时机。
- 定义删除对已有引用、对象和 agent 实例的影响。
- 删除内容、撤销授权与已有对象或 agent 实例的关系;仅移除命名入口不会使保留的确定引用失效。
- 临时值、不可达值与实例的回收时机,持久保存的数据及记忆的保留、归档与删除规则。
- 运行状态暂停、保存和恢复时引用与版本的一致性。
@@ -142,7 +177,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 换行字符、字符串扩展转义、更多字面量和运算符。
- 数值精度与舍入、除法、隐式转换与所有调用参数的求值顺序;不按固定机器位宽定义数值溢出。
正文中同级二元算术运算的组合顺序属于表达式提案,不规定所有调用的执行顺序。
同级二元算术运算从左到右组合属于表达式提案,不规定所有调用的执行顺序。
## 调用与数据
@@ -150,13 +185,30 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 显式等待、失败处理、缺失值、取消和超时的源码形式。
- 数据读取成员的声明、参数与结果类型。
- 一次结果、持续结果及其更新语义。
- 一次读取与持续关联的表达式、结果类型及建立方式;对象同步的具体边界见下一节。
- hook 的源码形式、触发或订阅关系、生命周期、关联解除和更新范围。
- 带业务修改的调用顺序、重复执行限制与失败行为。
- 更新代码时已有调用使用哪个版本。
- 已有调用继续保留所选定义,切换新定义或迁移运行实例的显式机制仍待定。
正常结果必须符合声明,未就绪或失败不能伪造为成功结果。Product.get 示例只展示成功路径。
## 跨端对象与同步
主要定义见[跨端对象与同步](../guide/11-resource-access-and-presentation.md#117-跨端对象与同步)。平台管理和存储对象、客户端建立本地副本并关联远程对象、通过网络交付数据及后续同步的方向已确定。它沿用 Object、资源 ID、类型及生命周期模型,不另设 PlatformObject 基础类型,也不自动把 class 变成持久化表。
不可变内容或定义更新产生新资源身份,确定引用不因同步而改指新对象;运行对象可以在类型允许的范围内保留身份并改变状态。平台对象、本地副本与同步关联分别具有生命周期,释放副本不等于删除平台对象。
尚未定义:
- 对象的登记与加载范围、本地副本的源码形式,以及完整或部分数据的取得规则。
- 一次读取与持续关联的建立、解除、可写性和结果类型;hook 与对象同步的具体关联方式。
- 状态版本、读取新鲜度、更新顺序及多对象一致性契约;不预先选定服务器权威、版本比较或合并算法。
- 本地修改的提交与保存确认、等待与失败状态,以及是否允许提前展示尚未被平台接受的修改。
- 多端同时修改的冲突处理、重试、去重和重复业务效果限制。
- 离线期间的读写、断线后的恢复、遗漏更新的取得及重新同步规则。
- 授权撤销、目标删除、关联解除与资源回收对已有副本的影响。
- 传输协议、类型编码及对象存储后端;这些实现选择不由逻辑对象身份决定。
## UI
尚未定义:
@@ -168,7 +220,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
- 布局单位、参数范围、负数、显式尺寸、约束与溢出。
- 主题、样式、文字测量和其他组件。
正文的官方组件示例使用结构示意,不定义调用语法,也不承诺免导入使用。
官方组件示例使用结构示意,不定义调用语法,也不承诺免导入使用。
## 资源访问与呈现
@@ -177,7 +229,7 @@ workspace 归属、key 前缀和整体授权模型已确定。名称细节、配
保留待讨论:
- 完整顶级类型的名称、集合及关系;已确定基础数值、文本、媒体和 GIS 类别,不代表完整类型层次已经确定。
- 顶级类型采用继承、接口、协议或其他机制的关系与声明形式。
- trait 能力组合及原生类型扩展的完整关系与声明形式。
- 可渲染类型的契约、普通类型的默认展示方式及自定义呈现。
- 同一资源具有多种呈现能力时的选择规则及未知类型的处理方式。
- 参数填写、默认或可省略参数、平台提供参数与访问触发调用的具体规则。
@@ -201,15 +253,38 @@ Agent 的语言资源地位、共有成员模型和核心职责已确定,主
成员函数是否默认向模型暴露为工具仍待定义;引用定义不自动启动实例或任务。MemorySaver 等外部库 API 不成为语言关键字或默认成员。
## REPL
[交互式会话(REPL)](../guide/14-repl.md)提出持续输入环境:声明准备定义,表达式检查后求值,结果对象可在后续输入中继续使用,远程等待与同步状态可查看。提案复用已有对象、权限、Preflight/inflight 和资源呈现规则;会话范围绑定、定义暂存、结果保留及交互调度尚未确定为正式契约。
尚未定义:
- 启动入口、控制命令、快捷键、多行输入边界、完整 REPL 文法及顶层绑定的正式形式。
- 会话名称的作用域、重复声明、重新绑定、失败后的环境变更,以及导入与名称冲突处理。
- 临时定义的资源登记、保存范围、共享 namespace 的编辑接口及新旧定义的绑定切换。
- 是否采用原生 Session、身份及权限传播、会话隔离与上下文切换。
- 输入的顺序与并发调度、待完成结果的引用、取消确认及未完成调用的结束行为。
- 结果查看方式、显式结果命名、更新通知与同步状态呈现;不预先引入隐式结果变量。
- 历史与会话状态的保存、对象保留根、恢复规则,以及避免业务调用被自动重放的具体契约。
- 断线、授权变化、客户端退出对平台任务、副本、同步关联及保存结果的影响。
本章的交互示意按文档规则推演,不代表已有启动命令或实际执行结果。REPL 提案不改写函数声明、普通调用和跨端对象的已有语义,也不选择存储后端或调度实现。
## 设计决定记录
2026-10-08 的用户设计决定明确了定义与运行时的 Preflight/inflight 生命周期、agent 作为语言结构及其核心职责,以及基础常量资源、统一数值、格式归一化和变量引用模型。未明确的关键字、成员关联、算术和编码选择继续保留为提案或未定义项。
同日确认 w 用于资源编辑,x 用于使用定义好的程序能力,业务调用产生写入不要求调用者成为 Editor。随后明确采用 workspace 归属模型:key 使用 workspace handle,注册创建默认个人 workspace,用户作为成员、操作用户及作者,权限按 workspace 整体管理。此决定替换原用户名归属模型;名称细节、迁移和仅执行授权等未定项不随之确定。
2026-10-09 的用户决定明确类型系统用于组织高级结构,类型标题使用代码中的名称。Unit、Null、Option、Result、State 等候选是否原生化、各项语法如何表达,仍需分别确定。
同日确定一切皆对象模型及 Object/Type 闭环:Object 是 Type 的实例,Type 是自己的实例并继承 Object,Object 没有父类型。实例化、继承和普通资源引用分别保存;class、trait、record、agent 构造入口自身也是对象。模型与资源 atom、独立 ID、确定引用及可达性保留统一。反射接口、构造入口类型、生命周期接入语法和登记粒度继续待定。
2026-10-13 的用户决定明确了平台管理和存储对象的方向:客户端获取远程数据时建立关联远程对象的本地对象,实际数据通过网络传递,并在后续保持同步。该方向纳入已有对象与资源身份模型;具体源码接口、保存确认、版本、冲突、离线及存储实现继续待定。
## 规范范围
本文定义源码及应有的语言效果。云端实体、持久化类、自动建表、通信、缓存、部署和编排实现不在本阶段规范中。
本文定义源码及应有的语言效果,包括平台对象存储、跨端副本关联与同步的概念边界。云端实体的实现、持久化类、自动建表,以及存储、通信、缓存、部署和编排的实现方案不在本阶段规范中。
S3 约定仅用于代码存储,不规定业务数据后端。平台负责跨端执行与通信的约定不指定传输协议、类型编码、调度算法或部署产物。
+4
View File
@@ -25,11 +25,15 @@
| 阶段与生命周期 | guide/05-preflight-and-inflight.md | Preflight 与 inflight 大小写;定义长期存续归入 Preflight,调用与实例存续归入 inflight;长期保存的运行状态不是定义;阶段不等于执行位置 |
| 词法 | guide/06-lexical-structure.md;appendices/formal-grammar.md | 草案中的标识符与字面量,不外推完整 Unicode、关键字或转义规则 |
| 资源与类型 | guide/07-types-and-classes.md | 基础常量、统一数值和媒体/GIS 归一化已确定,具体数值精度与编码未定;Number 为类型名提案;名义类型不凭成员相同兼容,class 不自动建表或具有 get |
| 类型系统 | guide/07-top-level-types/README.md 及各类型页;appendices/specification-status.md | Object ∈ Type、Type ∈ Type、Type ⊆ Object,Object 无父类型;实例化、继承、成员与依赖分别保存;class、trait、record、agent 构造入口自身也是对象,不预先定为保留关键字;平台按类型管理生命周期,atom 与 ID 维护资源图;反射及构造接口待定 |
| 表达式与变量 | guide/08-expressions-and-bindings.md | 变量可改变资源引用目标,不原地修改基础常量;let 可重绑性与赋值形式未定;结合与优先级不决定所有调用的求值顺序 |
| 调用 | guide/09-functions-and-calls.md | 普通调用保留值、类型、依赖和业务效果;不能擅自并行、重试或假定纯函数 |
| 数据 | guide/10-data-access.md | Product.get 是提案;业务 id 与 namespace key 不同;成功、缺失、失败、未就绪不能混写 |
| 跨端对象与同步 | guide/11-resource-access-and-presentation.md#117-跨端对象与同步;guide/07-top-level-types/README.md;appendices/specification-status.md | 平台对象沿用 Object 与资源 ID;本地副本通过网络取得数据和后续变化,不共享内存或保证瞬时一致;不可变内容更新产生新身份,运行对象按类型改变状态;具体接口、版本、确认与冲突策略未定 |
| 资源呈现与 UI | guide/11-resource-access-and-presentation.md;guide/12-ui-components.md | 普通函数返回可渲染值;函数查看、输入就绪与执行等待分别处理;顶级类型和构造形式未定,不补写专用 UI 文法或单根限制;官方组件来源未定 |
| Agent | guide/13-agents.md;appendices/specification-status.md | agent 已确认为语言资源;内部复用共有成员并承担工具、记忆、状态、路由、中断和上下文职责;骨架不代表成员关联、默认 API、委托或权限语法已确定 |
| REPL | guide/14-repl.md;appendices/specification-status.md#repl | 会话上下文、跨输入绑定、定义暂存和执行记录为提案;定义准备与调用执行分别处理,查看结果不重放业务调用;不擅自确认顶层文法、控制命令、原生 Session、并发或恢复策略 |
| 外部语言执行模型与框架比较 | appendices/language-keywords.md;appendices/language-runtime-lifecycles.md;appendices/framework-runtime-lifecycles.md | 区分语言规范、实现、宿主和框架;明确生命周期实体、入口、上下文、调度及清理;外部比较与执行契约研究不自动确认 Endorphin 的宏微任务、原生 Task、钩子或恢复 API |
所有主题同时核对 appendices/specification-status.md。涉及词形、产生式或组合约束时再核对 appendices/formal-grammar.md;纯措辞修改不必重读全书。
+4 -4
View File
@@ -20,16 +20,18 @@ Agent 作为语言声明纳入 namespace,可以实现新逻辑并引用已有
## 1.2 代码组织
每项独立登记的资源属于一个 workspace 和至少一级 namespace。workspace 通过唯一 handle 标识,namespace 通过完整 key 定位,例如:
独立登记的资源以资源 ID 识别,由 workspace 管理归属,namespace 提供命名与组织入口。workspace 通过唯一 handle 标识,namespace 通过完整 key 定位,例如:
```text
atelier:shop.pricing
```
`atelier` 是 workspace handle,`shop.pricing` 是 namespace 路径。用户以成员角色操作 workspace 中的资源;作者身份与资源归属分开记录。代码归属保存在外部上下文与索引中,正文无需声明自己的 namespace。
`atelier` 是 workspace handle,`shop.pricing` 是 namespace 路径。用户以成员角色操作 workspace 中的资源;作者身份与资源归属分开记录。代码归属保存在外部上下文与索引中,源码无需声明自己的 namespace。
代码以独立代码段存储,通过索引形成 namespace 的可见代码视图。namespace 是语言的代码组织单位,源码文件不承担这一职责。
多个 namespace 可以引用同一资源。移除命名入口不删除仍被保留程序引用的资源;具体引用行为及候选代码见[资源引用](07-top-level-types/references.md)。
## 1.3 声明与调用
代码归属:`atelier:shop.pricing`。该 namespace 定义价格计算函数:
@@ -63,6 +65,4 @@ Endorphin 将程序处理划分为两个阶段:
本书描述源码写法及其可观察行为,包括资源、代码归属、声明、类型、变量引用、调用、数据读取、UI 和 agent。通信协议、数据库绑定、缓存、部署和编排机制属于系统实现,不在语言介绍中展开。
下一章首先说明用户、workspace 与权限的关系,再介绍 namespace 与程序结构。
[下一章:用户身份与 workspace 权限](02-user-identity.md) · [目录](../README.md)
+3 -3
View File
@@ -38,15 +38,15 @@ atelier:shop.ui
`atelier:shop` 与 `market:shop` 是不同的 namespace,即使它们具有相同的路径或相同的代码内容。
只有 workspace handle 不能构成 namespace key。独立登记的资源还需要至少一级 namespace,完整格式见[namespace](03-namespaces.md)。workspace 本身的管理入口不由 namespace key 文法定义。
只有 workspace handle 不能构成 namespace key;命名入口需要至少一级 namespace,完整格式见[namespace](03-namespaces.md)。这一要求不表示资源必须始终拥有命名入口,资源自身通过独立 ID 识别。workspace 本身的管理入口不由 namespace key 文法定义。
## 2.3 归属上下文
资源与 workspace 的归属通过代码之外的 key 与索引成员关系关联。读取、编辑和处理代码时,系统使用该归属上下文。
资源与 workspace 的归属通过代码之外的管理记录关联,namespace key 与成员索引用于命名和查找。读取、编辑和处理代码时,系统使用该归属上下文;移除某个命名入口不丢失资源的归属记录。
函数名、变量名、注释、字符串和存储对象名均不定义归属 workspace。两段内容相同的代码分别关联不同 workspace 时,其归属上下文仍然不同。
正文中的 `use atelier:shop.pricing` 表示引用目标,不表示当前代码属于 atelier。例如,`market:shop.checkout` 可以引用 atelier 的逻辑,其自身归属仍是 market。
`use atelier:shop.pricing` 表示引用目标,不表示当前代码属于 atelier。例如,`market:shop.checkout` 可以引用 atelier 的逻辑,其自身归属仍是 market。
## 2.4 归属 workspace、操作用户与作者
+5 -3
View File
@@ -1,6 +1,6 @@
# 3. namespace
namespace 是资源归属、组织与检索的单位。对代码资源,系统使用 namespace key 查找索引,取得对应代码段,并形成可见代码视图。
namespace 是 workspace 内资源命名、组织与检索的单位。对代码资源,系统使用 namespace key 查找索引,取得对应代码段,并形成可见代码视图。资源本身以独立 ID 识别,名称与路径是查找入口。
函数、class 和 agent 定义,以及需要独立保存和引用的基础内容,都纳入这一组织体系。资源类别与变量引用见[资源、类型与类](07-types-and-classes.md);非代码资源的登记和成员定位形式仍待定义,不由代码视图的语法推导。
@@ -24,7 +24,7 @@ key 中的 handle 规则见[Workspace handle 与显示名](02-user-identity.md#2
## 3.2 最小归属
独立登记的资源必须同时具有归属 workspace 和非空 namespace 路径。下列形式缺少必要信息:
通过 namespace 命名入口检索资源时,key 必须具有 workspace handle 和非空 namespace 路径。下列形式缺少必要信息:
| 形式 | 缺少的内容 |
| ---------------------- | ---------------------------------- |
@@ -34,6 +34,8 @@ key 中的 handle 规则见[Workspace handle 与显示名](02-user-identity.md#2
workspace 显示名不能替代 handle。只有 workspace handle 不是完整 namespace key;workspace 本身的管理入口另行定义。
同一资源可以出现在多个 namespace 中,也可以在入口移除后由保留程序继续引用。非空路径是 key 的格式约束,不是资源生存的必要条件;确定引用和回收边界见[资源引用](07-top-level-types/references.md)。
## 3.3 层级语义
workspace 承担类似 repository 的整体资源与授权边界。其下第一级 namespace 与所有后续层级具有相同语义,`shop` 不构成额外权限边界或特殊 module 类型。
@@ -64,7 +66,7 @@ atelier:shop.pricing
引用目标:atelier:shop.pricing
```
当前代码的 key 由外部上下文提供;引用目标写入正文的 `use` 声明。引用不改变归属,也不自动授予访问权限。下一章说明声明与导入的组织方式。
当前代码的 key 由外部上下文提供;引用目标写入源码的 `use` 声明。引用不改变归属,也不自动授予访问权限。
## 3.6 Workspace 与资源成员
+6 -4
View File
@@ -2,7 +2,7 @@
一个 namespace 的代码视图由导入和声明组成。声明描述类型、逻辑、agent 或界面;导入使代码能够引用其他 namespace 中允许使用的声明。基础内容也可作为资源归属到 namespace,但其登记方式不由代码视图文法定义。
## 4.1 正文结构
## 4.1 程序结构
本文采用的程序结构为:
@@ -11,7 +11,7 @@
一个或多个 class、function 或 agent 声明
```
声明之间不使用逗号或分号。正文不含自身 namespace 声明,其归属来自外部 key 与索引。
声明之间不使用逗号或分号。源码不含自身 namespace 声明,其归属来自外部 key 与索引。
“一个或多个”表示同一代码视图可以包含任意数量的这三类顶层声明,至少包含一个;不要求每类各出现一次,也不要求一个 namespace 只保存一个定义。
@@ -22,11 +22,13 @@
| 一个或多个 agent | 一组模型驱动的行为定义 |
| 三类声明混合 | 类型、普通逻辑和 agent 共同组成程序 |
顶层声明与内部成员是不同位置。class 内的成员函数仍是 function,但属于类的成员作用域;agent 内的变量、函数或类型也保留其共有语义,并与 agent 实例或运行职责关联。内部成员不会仅因使用相同关键字自动成为 namespace 的顶层成员。
class 和 agent 构造出的具体类型对象属于 Type;Function 对象保存可调用逻辑。构造入口自身也属于对象体系,这些源码形式不预先规定它们是保留关键字。
顶层定义与内部成员是不同位置。class 内的成员函数仍是函数对象,但属于类的成员作用域;agent 内的变量、函数或类型也保留其共有语义,并与 agent 实例或运行职责关联。内部成员不会仅因采用相同构造形式自动成为 namespace 的顶层成员。
这里描述代码视图中的声明结构,不表示查看视图就实例化全部 class、启动全部 agent 或执行全部函数。函数体里的 let 和 return 仍遵守函数体规则,图片、文本等非代码资源的登记也不靠增加占位 class 或 function 表达。
agent 是语言声明,内部复用共有成员结构并增加 agent 作用域及运行关联。声明骨架仍为提案;工具、记忆和控制关联的具体写法见[Agent](13-agents.md)。
agent 构造具有名义身份的具体 Agent 类型对象,内部复用共有成员结构并增加作用域及运行关联。构造记法、工具、记忆和控制关联的具体形式仍为提案;其运行职责见[Agent](13-agents.md)。
这是一份逻辑代码视图的语法结构,不规定独立代码段的存储粒度或物理排列。代码段边界及视图组装规则见[代码存储与视图](../appendices/code-storage-and-views.md)。
+3 -1
View File
@@ -66,6 +66,8 @@ inflight 使用实际输入执行程序,产生程序可以观察到的结果
## 5.6 定义与运行时生命周期
定义、数据和运行实体都接入第 7 章的[Object 模型](07-top-level-types/README.md#object-的生命周期)。平台按具体类型管理对象的创建、准备、使用、存续与保留;Preflight 和 inflight 区分这些对象的生命周期职责,不表示两套彼此无关的对象体系。
**Preflight 生命周期**描述一个定义从创建、检查、建立引用关系,到持续可引用、更新或退出可用范围的存续。一次检查是其中的动作;检查完成不表示定义的生命周期结束。已保存的定义可以长期存在,并供多次 inflight 执行使用。
**inflight 生命周期**描述实际输入参与计算后,调用、对象、agent 实例和任务从产生、使用,到完成、释放或删除的存续。暂停或被保存的运行时状态仍属于这个层次,不因暂时没有代码执行而变成定义。
@@ -78,7 +80,7 @@ inflight 使用实际输入执行程序,产生程序可以观察到的结果
函数调用结束不要求返回值同时消失。返回值可以继续被引用或保存;对象也不因创建它的调用结束而必然被回收。需要长期保留的实例、agent 记忆和任务检查点仍是 inflight 数据,其保留与删除规则需单独定义。
定义的退出、运行时实例的删除和底层内存回收是不同事件。删除定义是否影响已有调用或实例,以及不可达值何时回收,见[规范状态](../appendices/specification-status.md#生命周期与定义更新)。
定义的退出、运行活动结束、底层内存卸载和资源内容回收是不同事件。移除命名入口不使已有确定引用失效;有效根可达的对象及必要依赖需要保留。授权变化和不可达资源的清理规则见[规范状态](../appendices/specification-status.md#生命周期与定义更新)。
传统 build time 常指构建发生的时段。这里的 Preflight 生命周期还覆盖准备后的定义存续,且不要求构建产物;不能把“定义长期存在”理解为平台一直在执行检查。
+10 -8
View File
@@ -1,6 +1,6 @@
# 6. 词法结构
词法规则将源码划分为标识符、关键字、字面量、运算符和标点。源码使用 UTF-8;空白与注释用于分隔词法单元。
词法规则将源码划分为标识符、语法标记、字面量、运算符和标点。源码使用 UTF-8;空白与注释用于分隔词法单元。
本章代码块展示局部词法形式,使用位置由后续表达式和声明规则决定,不是独立程序。
@@ -17,20 +17,22 @@ product_1
namespace 路径段使用标识符。workspace handle 属于平台命名规则,不直接使用源码标识符的定义。
## 6.2 关键字
## 6.2 语法标记与对象名称
本文语法使用以下关键字:
以下名称在候选语法中承担相应作用:
| 关键字 | 用途 |
| 名称 | 用途 |
| --- | --- |
| `use` | 引用 namespace |
| `class` | 声明数据结构 |
| `agent` | agent 声明骨架使用的关键字提案 |
| `function` | 声明函数 |
| `class` | 构造并命名类型对象的入口 |
| `agent` | 构造并命名具体 Agent 类型对象的入口 |
| `function` | 函数对象构造的候选记法 |
| `let` | 绑定局部结果 |
| `return` | 返回函数结果 |
这些关键字在相应产生式的位置出现。完整保留字集合见[规范状态](../appendices/specification-status.md#词法与表达式)。
class、agent 等构造入口自身也是对象;用它们建立的类型、函数和运行实例同样属于对象体系。trait、record 的候选构造形式遵循这一原则。源码中采用专门外形,不代表这些对象名称必须成为保留关键字。
use、let、return 表达依赖、绑定和控制动作。完整保留字集合,以及构造入口如何通过名称解析接入语法,仍需定义;产生式中的文字终结符只规定候选源码的拼写与位置。
## 6.3 数字
+189
View File
@@ -0,0 +1,189 @@
# 7.7 Object 与类型系统
Endorphin 采用一切皆对象的语言模型。Object 是所有语言对象的共同基础类型:数值、文本、容器、引用、类型定义、代码、函数及运行实体都属于这套对象体系。具体类型规定对象的结构、能力与生命周期,平台负责按这些规则准备、使用和保留对象。
类型系统同时描述两种关系:对象是哪个类型的实例,类型继承哪些类型。类型本身也是对象,因此 Product、Function、Agent 和 Object 自身都需要有实例类型;Type 将这些类型对象纳入同一体系。
顶级类型由平台原生支持。Object 提供对象基础,Type 描述类型对象,Number、Function 等规定具体对象类别。用户定义类型和多种 trait 能力也接入同一体系。平台负责按对象类型执行相应生命周期动作,实际使用仍可能等待、失败或被取消。
## 类型索引
对象模型采用 Object 与 Type 的闭环。成员接口、构造与泛型记法中的候选形式按[规范状态](../../appendices/specification-status.md#顶级类型讨论)区分。
示例采用候选记法:`name: T = value` 表达以类型对象 T 为约束的绑定,`(parameters) -> T { body }` 表达结果类型为 T 的函数体,`List<Number>` 表达带类型参数的容器类型。T 是说明记法中的占位名称。特定构造与成员操作的假设在各例旁说明。
class、trait、record、agent 表示相应定义对象的构造入口;这些入口自身也属于对象体系。`class Product { ... }` 等形式是创建并命名对象的候选记法。构造入口自身的具体类型与调用形式尚待定义,不将这些名称预先列为保留关键字。
| 阅读顺序 | 对象类型与构造入口 | 组织结构时承担的职责 |
| --- | --- | --- |
| 0 | [Object](README.md#object) | 统一对象身份、类型、引用关系和平台管理的生命周期 |
| 1 | [Bool、Number、String、Unit、Null](values.md) | 成员与表达式的基础类型;单值与空值候选 |
| 2 | [Tuple、record、List、Map、Set、Option、Result](collections.md) | 固定结构、容器和可组合的分支结构 |
| 3 | [Ref、Cell](references.md) | 结构之间的确定引用、可变关联和资源保留 |
| 4 | [Type、Trait、Code、class](definitions.md) | 组织类型对象、能力对象与代码对象 |
| 5 | [Function](functions.md) | 可调用结构的自身类型、扩展能力、实例与调用生命周期 |
| 6 | [Task、Stream、State、Session](execution.md) | 把执行、状态及上下文组织成可操作的结构 |
| 7 | [Agent、agent](agents.md) | 在共有类型基础上组合工具、记忆、状态与运行控制 |
整数与小数都使用 Number;精度与表示在这一类型内部讨论。文本、图片、音频等资源按自身的类型和操作使用,编码表示由相应资源的导入、导出及平台机制处理。
图片、音频、视频和 GIS 数据是具有各自表示及操作的对象类型;平台负责准备可用内容,业务代码使用类型化资源。各类别的格式与转换约束见[基础常量资源](../07-types-and-classes.md#基础常量资源)。
Type 对象描述类型,参数化的 List 等构造容器类型,Function 和 Agent 规定相应实例的执行语义。类型继承与多个 trait 的显式能力组合共同组织这些对象,能力关系不局限于一条父子继承链。Option、Result、Unit、Null、State 等候选是否原生化仍分别评审。
## Object
Object 是类型继承关系的根,没有父类型。每个对象都有自己的实例类型,类型自身也作为对象存在。对象通过其类型获得结构、操作与生命周期规则;平台沿这些关系检查和准备对象。
### 实例化线
实例化线回答“这个对象是谁的实例”。以 `x ∈ T` 表示对象 x 的直接实例类型是 T。商品对象 tea 是 Product 的实例,Product 这个类对象则是 Type 的实例:
```text
tea ∈ Product
Product ∈ Type
```
这不是一条继承链。tea 保存商品字段,Product 保存商品类型的定义;二者是不同对象。查询 tea 的类型得到 Product,再查询 Product 的类型得到 Type。
外部归属为 `atelier:shop.data` 的候选类型定义:
```endorphin
class Product {
name: String
price: Number
}
```
函数体片段引用上述 Product。构造采用命名字段形式;typeOf 暂表示查询直接实例类型:
```endorphin
let tea: Product = Product { name: "Tea", price: 90 }
let productType: Type = typeOf(tea)
let metatype: Type = typeOf(Product)
```
productType 指向 Product,metatype 指向 Type。Product 本身可以传入类型参数、被其他对象引用或放入容器;它作为对象存在不依赖是否已经创建商品实例。typeOf 和构造记法是本例的接口候选。
### 继承线
继承线回答“这个类型继承谁”。以 `A ⊆ B` 表示 A 是 B 的子类型;这里的符号表达类型关系,不把类型对象当成普通集合。
```text
Product ⊆ Object
Number ⊆ Object
Function ⊆ Object
Agent ⊆ Object
Type ⊆ Object
```
`Product ⊆ Object` 与 `Product ∈ Type` 可以同时成立:前者说明 Product 实例具有 Object 的共同基础,后者说明 Product 类型对象本身由 Type 描述。Product 不需要继承 Type,tea 也不会因为 Product 是 Type 的实例而成为类型定义。
用户类型通过直接或间接继承接入 Object。采用 `class Product { ... }` 时,未指定其他父类型的类以 Object 为基础;显式父类型的候选形式是 `class Product: Object { ... }`。更具体的继承、成员复用和构造顺序仍需规定。
Product 与具有相同字段的 ListedProduct 保持不同的名义身份。两者都继承 Object,不会因此互相兼容。多个 trait 的能力组合通过明确的实现关系建立,不由同名成员推导,也不与对象的直接实例类型混为一谈。
### Object 与 Type 的闭环
Object 自身是一个类型对象,它的实例类型为 Type。Type 自身也是类型对象,其实例类型仍为 Type;在继承线上,Type 继承 Object:
```text
实例化:Object ∈ Type
实例化:Type ∈ Type
继承: Type ⊆ Object
根类型:Object 没有父类型
```
因此不用在 Type 之上不断增加 Type 的类型。`Type ∈ Type` 描述实例化关系,`Type ⊆ Object` 描述继承关系,二者没有冲突。平台提供 Object 和 Type 的这个基础闭环,其余对象据此获得实例类型与继承关系。
候选反射片段采用 typeOf 查询实例类型,basesOf 查询直接父类型;返回列表的记法用于说明关系:
```endorphin
let objectType: Type = typeOf(Object)
let typeType: Type = typeOf(Type)
let typeBases: List<Type> = basesOf(Type)
let objectBases: List<Type> = basesOf(Object)
```
objectType 与 typeType 都指向 Type,typeBases 为 `[Object]`,objectBases 为 `[]`。typeOf 与 basesOf 需要分别保留这两种查询含义,具体接口名尚待确定。
数值与函数同样可以明确归类:`90 ∈ Number`、`Number ∈ Type`、`Number ⊆ Object`;定价函数 discountedPrice 则满足 `discountedPrice ∈ Function`、`Function ∈ Type`、`Function ⊆ Object`。继承关系的两端必须是类型对象,不能把一个具体价格或函数值写成子类型。
以 Object 标注持有对象不会改变它的直接实例类型,也不会创建另一份内容。例如 `let item: Object = tea` 仍持有 tea;商品字段与专门操作的使用需要对应类型或显式能力。所有对象共有对象基础,各类型仍保留自己的操作契约。
## Object、atom 与资源 ID
对象作为可独立识别、保存和引用的资源单元时称为 atom。资源 ID 标识这个对象,平台通过 ID 解析引用、准备对象并维护其依赖。ID 是逻辑身份,不是某台机器的内存地址;对象暂时没有加载到物理内存,也仍可被引用。
平台管理的对象可以在存储中保留,并在不同执行端准备本地副本;各副本通过资源身份关联,数据和后续变化通过网络传递。这不引入新的基础类型,也不要求所有临时值永久登记。副本与平台对象的区别、同步及跨端生命周期见[跨端对象与同步](../11-resource-access-and-presentation.md#117-跨端对象与同步)。
atom 描述对象的资源身份,不是 Object 下面另一种内容类型。一个数值对象可以是 atom,一个类型对象、一份函数对象或包含多个定义的 Code 对象也可以是 atom。组合对象有自己的身份,其中被独立引用的成员保留各自身份;组合整体与成员不会因此成为同一个资源。
沿用 Product 与 tea。若二者独立登记,可以分别用 `product-type-1` 和 `tea-1` 表示其资源 ID;这些字符串只是身份示意,不规定 ID 格式。tea 的类型关联指向 Product 的资源 ID,Product 的实例类型关联指向 Type 的资源 ID;Product 的父类型关联则指向 Object 的资源 ID。Type 和 Object 本身也作为对象单元参与这套索引。
因此,实例化线与继承线都能用对象之间的确定引用保存,但引用必须保留各自的含义。tea 指向 Product 的类型关联不能解释成继承;Product 指向 Object 的父类型关联也不能解释成“Product 的直接实例类型是 Object”。除此之外,tea 的 name 和 price 是成员关联,函数引用另一份代码是定义依赖。这些边都连接对象,平台根据边的含义检查结构并执行生命周期。
workspace 记录资源归属、成员及授权,namespace 为资源建立名称与浏览位置。例如 `atelier:shop.data` 中的 Product 入口指向 `product-type-1`;另一个 namespace 可以为同一类型对象建立别名。添加别名不创建新类型,移除别名不删除仍被 tea 或其他保留对象引用的 Product。管理记录本身具有平台身份,其管理职责不意味着它自动成为业务代码中的资源类型。
名称只用于查找与展示。保存代码时,平台将所采用的类型和函数绑定到确定资源 ID,并保存传递依赖。以后 namespace 中的同名入口改指新对象,已经保存的代码仍持有原来的对象引用。
例如定价函数原对象的资源 ID 为 `pricing-1`,结算程序引用它。修改定价逻辑后保存新对象 `pricing-2`,再将 discountedPrice 的命名入口改指新对象,原结算程序仍调用 `pricing-1`。要采用新逻辑,需要保存绑定 `pricing-2` 的新结算程序。旧对象从目录中消失,也不会使仍保留的调用关系失效。
内容或定义对象的修改产生新资源身份;Cell、Task 等运行对象则可以在类型允许的范围内改变状态而保留身份。资源 ID 回答“是哪一个对象”,不能单独回答“对象此刻的状态是什么”;固定历史内容需要相应的快照对象。
回收依据有效保留根的可达性。保留的程序、运行活动或历史记录如果需要某个对象,其必要类型定义和代码依赖也须保留。没有有效根能到达的一组互相引用对象可以进入回收范围;循环引用本身不要求永久保留。物理内存表示可以卸载并重新准备,仍需保留的持久资源内容不能随之删除。临时对象的独立登记粒度、保留根范围及回收时机仍需定义。
## Object 的生命周期
平台管理每个对象适用的生命周期,具体类型和显式能力决定允许哪些动作。这里描述共同职责,不规定所有类型采用同一组源码方法或状态枚举。
创建对象时,平台建立其身份、直接实例类型及所需成员关联。准备对象时,平台依据具体类型检查结构、解析确定依赖并取得可用表示。使用对象时,Number 参与数值运算,Function 接受调用,Agent 实例处理任务;每种操作产生的结果与活动也属于对象体系。
状态存续由具体类型约束:不可变内容更新产生新对象,可变运行对象维护允许的状态迁移。任务完成或实例关闭结束相应活动;释放可重新准备的内存表示只改变加载状态。对象是否还能回收,最后由保留根及引用关系判断。
Preflight 管理定义对象的检查、准备和持续可引用,inflight 管理实际调用、数据对象及运行实例。长期保存的 Task 状态仍是 inflight 对象,已就绪的 Function 定义仍可长期存续;平台执行生命周期不意味着持续执行对象里的业务代码。
已保存的内容或定义被修改时,产生新的资源对象及其确定引用关系。Cell、会话或任务的运行状态则可在允许的规则内变化,固定运行对象身份不承诺其状态不变。定义对象、运行对象与确定内容快照需要分别选择。
从 namespace 移除入口、标记废弃、结束运行活动、卸载物理内存和回收资源内容,是不同生命周期动作。前两项不自行改写已有程序依赖;只要仍能从有效保留根到达对象,就必须保留必要内容与依赖。保留与调用授权分别判断,具体规则见[Ref、Cell](references.md)。
## 类型怎样组成高级结构
以下候选声明的外部归属为 `atelier:shop.pricing`。Function 的类型参数约束参数及结果,List 约束元素类型,Cell 约束可变位置的目标类型:
```endorphin
class PricingPolicy {
name: String
enabled: Bool
rules: List<Function<(Number, Number) -> Number>>
currentAmount: Cell<Number>
}
```
PricingPolicy 是 Type 的实例,并继承 Object;按它构造的实例以 PricingPolicy 为直接实例类型。实例通过成员组织 String、Bool、List 和 Cell 对象。List 保存 Function 对象,Cell 保存允许更新的目标引用;这些关系进入平台维护的资源图。每个对象具有自己的类型与生命周期,组合对象的存续不要求所有成员同时开始或结束。
trait 对象描述显式组合的能力,Code 与 Type 支持检查和组织定义,Task、Session 与 Agent 管理运行实体的存续。类型约束作用于整个结构及其成员,并不只作用于函数结果。
## 判断一种能力是否需要原生类型
| 候选安排 | 适用情况 | 对使用者的影响 |
| --- | --- | --- |
| 平台原生类型 | 平台需要直接理解其表示、调用、等待、状态或外部访问语义 | 获得统一准备与使用行为,并需要明确稳定契约 |
| 平台标准支持的扩展类型 | 需要专门的媒体、空间或数据操作,但不宜把全部领域形式固定在语言核心 | 扩展接入统一类型与引用体系,具体支持范围可独立演进 |
| 普通用户类型或 trait 实现 | 行为可以通过已有类型和操作组合表达 | 复用平台机制,同时由定义负责其额外约束 |
“由平台支持”规定可观察行为,不规定必须使用何种宿主语言或硬编码方式。列表遍历、媒体查看等操作可以共享实现机制;代码文档不据此指定缓存、通信、部署、自动建表或持久化类方案。
## 全部条目共用的边界
**资源身份与类型身份。** 资源 ID 回答引用了哪个对象或定义;类型身份回答值属于哪个声明类型。两个资源可以具有同一类型,两个内容相等的资源也不必是同一个资源。代码修订与名义类型身份的演进规则另行定义。
**定义与运行中的值。** 保存函数对象不会启动调用,引用 Product 类型对象不会创建商品实例,引用 PricingAssistant 类型对象不会启动任务。运行中生成的新定义需要经过 Preflight 后成为可用定义。
**准备与业务执行。** 准备资源应保留原本的调用、数据依赖和业务效果约束。查看类型或检查定义不自动执行其业务代码,平台支持某项操作也不保证每次都成功。
**类型与开放语义。** 可读、可调用等操作能力不能代替用途、角色和意图的全部意义。业务语义可以具有额外的描述与判断依据,不以结构匹配或评分自动决定归属。
**呈现与调用。** 类型可以提供查看或呈现能力,但可调用不代表查看时自动执行;能呈现图片不代表所有类型都继承界面类型。相关行为以[资源访问与呈现](../../guide/11-resource-access-and-presentation.md)为依据,具体 trait 和默认查看器仍待定。
[前文:资源、类型与类](../07-types-and-classes.md) · [Bool、Number、String、Unit、Null](values.md) · [规范状态](../../appendices/specification-status.md#顶级类型讨论) · [文档目录](../../README.md)
+105
View File
@@ -0,0 +1,105 @@
# 7.14 Agent、agent
Agent 是关联工具、记忆、状态、路由、中断和上下文管理的对象类型。Agent 类型对象是 Type 的实例,并继承 Object。agent 是构造具体 Agent 类型对象的入口,其自身也属于对象体系;构造入口的具体类型与调用形式待定。
本页代码是候选设计,外部归属为 `atelier:shop.agents`。工具声明、实例操作及配置记法用于展示可以怎样编写和使用 Agent,不表示这些成员已经定稿。模型配置、工具调用授权与用户输入均需在实际运行前就绪。
Agent 定义、具体实例、任务、记忆与状态都由 Object 组成。平台负责准备定义对象、建立实例关联并执行相应运行生命周期;函数工具和记忆内容可以直接引用已有资源对象,组合后的 Agent 也可以独立登记为 atom。
## agent
agent 构造的 PricingAssistant 是类型对象,保存执行与控制规则,以及确定绑定的函数和其他定义资源。平台准备这些关系,并检查已知的参数、结果和能力约束。读取或引用类型对象不会自动调用模型、执行工具或创建实例。
候选声明把工具关系直接关联到函数资源,而无需为同一工具复制一份代码:
```endorphin
discountedPrice: Function = (price: Number, discount: Number) -> Number {
return price - discount
}
agent PricingAssistant {
input: Type = String
output: Type = String
tools {
calculate = discountedPrice
}
memory {
history: List<String> = []
}
state {
lastAmount: Option<Number> = none
}
}
```
本方案中 input、output 是输入与最终结果的类型配置,tools 是可用工具的显式关联,memory 和 state 分别声明记忆与运行状态。它们是候选配置角色,不因使用相同名字就成为所有 class 的特殊字段。
保存这段定义时不会计算价格。只有一次运行确实调用 calculate(100, 10),该工具调用才得到 90。声明 lastAmount 也不自动建立更新路由;要把工具结果写入它,还需要明确的状态更新规则。这样可以判断“原生认识 Agent”与“平台替用户猜测所有控制逻辑”的边界。
可以把 Agent 作为代码定义的专门形式,也可以复用通用定义协议。Agent 与 Function 都可以有输入输出约束,但 Agent 还管理模型上下文与工具选择;是否实现统一调用 trait 应显式决定,不能让所有 Agent 自动等同于一次普通函数调用。
**待定重点:** 构造入口与具体 Agent 类型的继承形式、工具暴露和描述、配置成员形式、控制与状态关联,以及 Agent 是否具有可调用能力。
## Agent
Agent 描述实例的共同运行能力,Type 描述 Agent 类型对象本身。采用 PricingAssistant 继承 Agent 的候选关系时,两条线分别是:
```text
实例化:first ∈ PricingAssistant,PricingAssistant ∈ Type,Agent ∈ Type
继承: PricingAssistant ⊆ Agent ⊆ Object
```
引用 PricingAssistant 类型对象的函数体片段:
```endorphin
let definition: Type = PricingAssistant
let baseType: Type = Agent
```
definition 引用 PricingAssistant,baseType 引用 Agent,二者都是 Type 的实例,尚未创建运行实例。不能用实例基础类型 Agent 替代定义对象的实例类型 Type;first 才是具有 Agent 能力的运行实例。
平台维护类型对象的确定代码依赖与准备状态。定义内容修改产生新类型对象,已经存在的实例仍关联原来的确定定义。具体名义类型身份如何跨修订演进,仍需规定。
## PricingAssistant
Agent 实例按定义建立,保存具体上下文和状态。一个定义可以创建多个实例,一个实例可以处理多个任务;任务完成不必结束实例,实例结束也不自动删除长期保留的资源。
PricingAssistant 实例以 Object 为共同基础,具有该声明的具体名义类型。平台执行它的创建、运行控制、暂停恢复及结束过程,并按引用图管理相关对象。实例结束与销毁资源内容分开处理;保留的任务、记忆或历史关系仍可能保住相关资源。
候选函数体片段使用前述 PricingAssistant。create 暂表示创建实例,submit 接收本次输入并返回任务,close 结束实例:
```endorphin
let first: PricingAssistant = PricingAssistant.create()
let second: PricingAssistant = PricingAssistant.create()
let job: Task<String> = first.submit("原价 100,优惠 10,请使用定价工具计算。")
let answer: String = await job
first.close()
```
本候选以 PricingAssistant 作为具体实例类型,为 first 与 second 分别初始化 history 和 lastAmount。Function 工具、List<String> 记忆、Option<Number> 状态及 Task<String> 任务共同组成这个高级结构。first 接收请求不会自动改变 second 的上下文。若模型以 100、10 调用工具,确定的工具结果为 90;完整自然语言回答不能伪装成确定执行结果。
create、submit 和 close 是本方案提出的平台操作名;也可以改用构造表达式、统一调用或任务投递协议。选择应以实例与任务的语义是否明确为依据,而非强制所有类型都增加同名接口。
本例只展示任务结束后关闭实例。仍有任务运行时怎样关闭、能否取消、人工暂停后怎样恢复,都需要独立契约。把状态保存下来不等于自动解决工具重复执行或外部业务效果的恢复。
同一实例的多任务可以选择隔离、会话内共享或明确共享资源;来自同一定义不意味着共享全部可变状态。实例引用哪份定义及依赖,也与 namespace 当前入口分别处理。采用新定义需要迁移规则,入口改名或改指不能隐式修改旧实例。
**待定重点:** 实例类型与身份、任务接口、记忆与状态的共享范围、暂停恢复、定义迁移,以及执行授权。开放语义判断仍需上下文,类型正确不保证 Agent 的每次决定都正确。
## 与其他顶级类型的组合
| Object 类别 | 本例中的位置 | 生命周期 |
| --- | --- | --- |
| Function | discountedPrice 工具定义 | 可持续引用,具体调用另有执行过程 |
| Agent 定义 | PricingAssistant | Preflight 准备并保留的定义 |
| Agent 实例 | first、second | inflight 中各自存续的上下文与状态 |
| 任务 | job | 一次输入到完成、失败或取消的过程 |
| String、List、Option 对象 | 输入文本、history、lastAmount | 按具体类型、引用图及保留规则管理 |
工具可以是函数资源,记忆可以是文本、媒体或结构化值,检查点可以是有恢复含义的状态记录。因此不必仅凭名称再建立 Tool、Memory、Checkpoint 三种顶级类型;是否原生化应依据独立操作和检查需求决定。
[Task、Stream、State、Session](execution.md) · [类型系统](README.md) · [下一章:表达式与绑定](../08-expressions-and-bindings.md)
+178
View File
@@ -0,0 +1,178 @@
# 7.9 Tuple、record、List、Map、Set、Option、Result
本页逐项讨论 Tuple、record、List、Map、Set,以及 Option、Result 候选。它们提供固定成员、重复元素和分支结构的组合能力,用于组织 class 字段、变量和其他资源。参数类型的基础见[Bool、Number、String、Unit、Null](values.md);最终清单、泛型记法与构造形式仍待评审。
本页示例归属为 `atelier:shop.pricing`;声明与函数体片段分开给出。类型参数、构造器与成员名均采用[总览](README.md)的候选记法,各节在自己的假设下推演结果。
这些结构都属于 Object:容器或分支对象通过成员组织其他对象,组合整体也可以成为一个独立资源 atom。平台管理整体的类型、内容或状态及其引用关系,不要求每个成员与整体具有相同的资源身份或结束时机。
具体容器类型本身也是类型对象。例如价格列表是 List<Number> 的实例,List<Number> 类型对象属于 Type,并通过容器类型关系接入 Object。参数化类型的生成、复用及父类型细节仍需规定;容器对象、元素对象与容器类型对象分别保留身份。
| Object 类别 | 平台理解的结构 | 生命周期职责 |
| --- | --- | --- |
| Tuple、record | 固定位置或命名成员 | 检查成员约束,保留组成对象的有效引用 |
| List、Map、Set | 元素、键值或成员关系 | 按候选可变性规则产生新内容或更新明确的运行实例 |
| Option、Result | 选定分支及其成员类型 | 保留当前分支的对象关系,切换方式由可变性规则决定 |
不可变容器内容更新会产生新对象;它包含的运行实例对象仍按自己的状态规则活动。平台回收整体之前,需要考虑保留根与成员图,不能按“它有几个内部成员”判断是否仍被使用。
## Tuple
Tuple 按位置组合固定数量的成员,不同位置可以具有不同类型。例如一种商品标注结构可以用 String 保存名称、Number 保存价格,两项组成一个整体。
平台需要理解各位置的类型、固定长度、构造、位置访问以及可能的解构。Preflight 可以检查静态已知的数量和位置关系;动态构造及边界处理仍需对应规则。
候选一是采用位置型元组,适合短小、局部的多结果组合;候选二是要求这类结果都使用命名记录或 class。前者减少临时声明,后者让每个结果的意义更明确。建议元组作为候选保留,同时避免用很长的元组承担公共业务数据结构。
候选函数体片段;本方案采用从零开始的位置索引:
```endorphin
let quote: Tuple<String, Number> = ("Tea", 90)
let name: String = quote[0]
let amount: Number = quote[1]
```
name 为 `"Tea"`,amount 为 90。Tuple 的参数固定两项成员类型,`quote[2]` 超出已知长度,应在 Preflight 被拒绝。使用者必须知道位置含义;字段增多时,下一节的 record 方案更容易阅读。Tuple 名称、参数列表和位置构造都是待选记法。
**待定重点:** 位置访问与解构、单元素及空元组、元组类型身份、协变等兼容规则。元组类型的组合规则不能自动推广成用户 class 按成员结构兼容。
## record
记录按字段名组织值,适合表达一组有明确含义的数据,例如“商品名称与当前展示价格”。它与映射的区别在于字段集合和各字段类型可以由定义固定;映射通常使用同一键值规则处理数量可变化的条目。
记录与 class 是否需要分别存在是本项的主要选择。候选一是只提供名义 class,用轻量写法减少样板;候选二是通过 record 构造入口创建以数据为主的名义类型对象。两种入口自身都是对象,是否分开取决于所构造类型的能力差异。
建议暂不把匿名字段集合直接认定为某个用户声明类型。即使商品记录的字段与 Product 完全相同,也仍需明确构造、转换或能力实现关系。允许简洁的记录字面量,与采用结构类型兼容不是同一个决定。
平台候选职责是字段约束、构造、访问和内容更新结果的表示。是否生成比较、复制或呈现能力,应单独决定。
独立名义记录方案的候选声明:
```endorphin
record PriceQuote {
name: String
amount: Number
}
```
候选构造与读取片段:
```endorphin
let quote: PriceQuote = PriceQuote { name: "Tea", amount: 90 }
let amount: Number = quote.amount
```
amount 为 90。PriceQuote 是 Type 的实例,quote 是 PriceQuote 的实例。`PriceQuote { ... }` 明确指定名义身份,不能仅用一组同名字段冒充任意其他名义类型。record 与 class 可以选择不同的构造入口,但都产生同一对象体系中的类型与实例。
**待定重点:** 独立记录类型的必要性、名义身份、字段默认值、开放字段、字段更新,以及与 class 的关系。
## List
列表表达有顺序、长度可变化、可包含重复元素的一组值,例如商品列表。元素约束可以用泛型表达,但本页不决定其正式写法。
平台可提供构造、长度、按位置访问、遍历、切片和生成新列表。传入的遍历函数仍是普通调用:如果它带有业务效果,列表操作不能自行增加并行或重试语义。
候选一是不可变列表内容,增删元素产生新列表,变量改指新结果;候选二是有独立实例身份的可变列表。前者与基础内容模型容易组合,后者需要明确别名、并发修改和迭代期间变化。建议先定义不可变列表,把可变行为作为显式能力或独立实例方案讨论。
两个变量引用同一不可变列表时,一个变量改指新列表不改变另一个变量的结果。列表里的元素若是运行实例引用,列表自身不变也不保证这些实例的状态不变,需要保留这个区别。
采用不可变列表方案的候选函数体片段;append 返回新列表,索引暂从零开始:
```endorphin
let prices: List<Number> = [100, 90]
let more: List<Number> = prices.append(80)
let first: Number = more[0]
```
prices 仍为 `[100, 90]`,more 为 `[100, 90, 80]`,first 为 100。容器操作没有修改原资源;越界如何表达、混入文本是否允许通过联合类型表达,都仍需另外选择。
**待定重点:** 索引起点、越界、切片区间、异构元素、空列表的类型推断、相等性,以及列表是否允许延迟求值。延迟列表与运行时 Stream 的关系见[Stream](execution.md#stream)。
## Map
映射把键关联到值,适合按商品业务编号查找库存或价格。这里的业务编号是映射的键,不自动等于平台资源 ID。
平台可提供按键查找、遍历、建立新绑定和移除绑定。键需要有明确的相等规则;如果实现采用哈希索引,语言仍应说明可依赖的相等行为,不将底层哈希碰撞直接暴露成键相同。
不可变映射与可变映射实例可以采用与列表相同的候选分工。建议先以不可变内容加显式引用更新解释变化,避免因为“映射”一词就隐含共享状态。
缺少键、键存在而值表达缺失、查找失败是不同情况。候选方案可以让查找返回可选值,或使用明确的结果分支;不能用零、空文本或任意占位对象代替缺少条目。
候选函数体片段;Map 构造、返回可选值的 get,以及返回新映射的 put 是本例选择:
```endorphin
let prices: Map<String, Number> = Map { "tea": 90 }
let found: Option<Number> = prices.get("tea")
let missing: Option<Number> = prices.get("coffee")
let updated: Map<String, Number> = prices.put("tea", 85)
```
found 为 some(90),missing 为 none;updated 中 tea 对应 85,prices 中仍对应 90。这里选用了可选值候选,以区分“不存在”与“价格为零”,没有确定平台全部查找操作都必须使用 Option。
**待定重点:** 键的允许类型、键相等性、重复键的构造行为、遍历顺序、缺失表达,以及可变实例的更新规则。
## Set
集合表达不重复的成员,例如参与某次优惠的商品编号集合。顺序是否可观察需要显式约定,不能从编辑器展示的排列推导出语言保证。
平台可提供成员判断、遍历、并集、交集和差集等操作。去重依据必须明确:资源 ID 相同、内容相等与业务上属于同一商品,可能得出不同结果。
候选一是按元素类型的明确相等规则去重;候选二是构造时提供一个确定的键提取或相等能力。前者简单,后者适合按业务编号去重,但新增了需要绑定和保留的代码依赖。建议先确定类型的相等机制,再决定是否支持逐集合自定义去重规则。
对可变对象状态进行去重时,成员状态改变可能影响成员关系。可以限制为稳定键,或明确规定重新计算行为;不能留下“加入后自己变成另一个成员”的隐含效果。
候选函数体片段;本例按文本值相等去重,add 返回新集合:
```endorphin
let eligible: Set<String> = Set { "tea", "tea", "coffee" }
let hasTea: Bool = eligible.contains("tea")
let sameMembers: Set<String> = eligible.add("tea")
```
eligible 和 sameMembers 都只有 tea、coffee 两个成员,hasTea 为 true;本例不承诺遍历顺序。改为保存商品实例后,必须先决定按实例身份还是业务编号判断相等,不能直接套用文本去重规则。
**待定重点:** 顺序、相等性、自定义去重、稳定键、集合与列表的转换,以及可变集合的必要性。
## Option、Result
Option 和 Result 是带类型参数的分支结构候选。它们可以作为字段、容器元素或独立值,是否由平台原生提供仍待决定。
Option<T> 可以提议由两种分支组成:some 携带一个 T 类型成员,none 不携带该成员。比如优惠配置中的 Option<Number> 可以区分未配置优惠额与明确配置为 0;是否使用此结构不取决于它来自哪个函数。
Result<T, E> 可以提议由 ok(T) 和 err(E) 两个分支组成,两个分支具有各自的成员类型。它能保存在验证状态或任务记录里,也能参与更大的结构;是否另有 Error 类型、是否与异常机制并存,仍需讨论。
平台可以对分支处理和类型使用提供检查。若采用显式分支,使用内部成功值前需要处理其他可能情况;若采用异常传播,则需要明确调用边界和未处理失败的结果。两种方案均不能以默认业务值隐藏失败。
建议按“是否存在”与“操作是否成功”分别建模,并允许组合表达。是否由平台原生支持、由普通名义变体类型提供,或者以其他机制表达,需要与分支构造和模式匹配设计一起选择。
候选函数体片段;Result 的第二个类型参数暂直接使用 String 表达失败信息:
```endorphin
let found: Result<Option<Number>, String> = ok(some(90))
let missing: Result<Option<Number>, String> = ok(none)
let failed: Result<Option<Number>, String> = err("读取失败")
```
三项分别表达“成功且有价格”“成功但没有条目”“操作失败”。这只是构造方式的候选;分支处理语法尚未选择,程序不能未经处理就把任意一项当作 Number 参与减法。
组合结构的候选声明,外部归属仍为 `atelier:shop.pricing`:
```endorphin
class DiscountConfiguration {
ranges: List<Tuple<Number, Number>>
prices: Map<String, Number>
eligible: Set<String>
fallback: Option<Number>
validation: Result<Unit, String>
}
```
ranges 的每项具有两个 Number 成员;prices 使用 String 键与 Number 值;eligible 约束不重复成员;fallback 和 validation 则保留各自的分支结构。类型参数在这里决定 class 的成员组织方式,完整结构不需要先作为函数结果出现。
## 结构化值的共享边界
不可变容器可以包含确定内容引用,也可以包含明确的运行实体引用。容器内容不变只固定成员引用,不自动冻结被引用服务、数据库或任务的状态。
本页使用的“元素类型”“键值类型”和分支关系是泛型需求说明,不确认具体尖括号语法、推断、变型或继承规则。所有容器的生命周期与有效引用保留统一采用[引用讨论](references.md)。
[Bool、Number、String、Unit、Null](values.md) · [类型系统](README.md) · [Ref、Cell](references.md)
+151
View File
@@ -0,0 +1,151 @@
# 7.11 Type、Trait、Code、class
Type 描述类型对象,Trait 候选描述能力定义对象,Code 描述代码结构对象。class 与 trait 是创建相应定义对象的构造入口,其自身也属于对象体系;构造入口的具体类型和调用记法仍待定义。类型对象可以被引用、检查和组合;按类型创建的实例具有自己的成员与状态。
Type、Trait、Code 及 class 定义统一是 Object。定义对象保存具体结构、能力与确定依赖,平台负责检查、准备、持续保留和退出可用范围。按定义建立的实例是另外的 Object,具有自己的类型身份、内容或运行状态。
定义的准备与存续归入 Preflight,定义被使用后产生的对象、调用和任务归入 inflight。对定义做普通的数据变换可以在运行任务中发生;变换产生的新可执行定义需要重新经过 Preflight。
## Type
Type 是类型对象的实例类型,Type 本身也是 Type 的实例。Object 是 Type 的实例,Type 在继承线上继承 Object,而 Object 没有父类型。这套闭环使类型定义本身也能作为对象被引用、传递和保存。
Product 是 Type 的实例,商品对象则是 Product 的实例;Product 继承 Object,不继承 Type。Number、Function 与 Agent 这些类型对象也属于 Type,其具体实例按各自契约使用。查询对象的实例类型与查询类型的父类型是不同操作,不能混为同一条关联。
类型定义描述实例的结构及其允许用法。把类型定义作为资源保存,可以支持查询参数类型、为函数绑定类型参数、向工具展示结构,以及保留用户声明的名义身份。
类型对象可以作为值传递和引用。平台操作的具体接口包括取得定义身份、查看获准查看的结构、核对实例类型和检查已声明的能力关系;比较、动态构造和修改后的检查过程仍需与泛型及反射规则一起确定。
名义身份继续作为用户声明类型的依据。两个 class 字段相同,不自动成为同一个类型。新修订如何保留或改变名义身份也需独立规则,不能简单地把每次代码资源 ID 的变化直接当成所有公开类型都不兼容。
候选一是只暴露只读的类型描述与明确的构造过程;候选二是允许程序生成和变换类型定义。第二种能力适合 Agent 生成代码,但生成结果必须经过检查,不能通过修改已保存的描述对象立即改变现有类型。
**待定重点:** 泛型种类与约束、反射接口、运行时生成定义、名义身份演进和显式转换关系。
候选函数体片段,外部归属为 `atelier:shop.pricing`。本方案把类型定义作为 Type 值,提供只读描述操作:
```endorphin
let amountType: Type = Number
let rootType: Type = Object
let typeObject: Object = amountType
let label: String = amountType.name
let sameDefinition: Bool = amountType == Number
```
label 为 `"Number"`,sameDefinition 为 true。amountType 指向 Number 类型对象,rootType 指向 Object 类型对象;typeObject 仍持有同一个 Number 类型对象。Number 是 Type 的实例,数值 90 则是 Number 的实例。name 只是展示信息;同名定义不能仅凭文本判为同一类型。name 和定义比较是本例的候选接口。
## trait、Trait
trait 构造能力定义对象,表达可以显式实现和组合的一组能力要求。一个具体类型可以实现多个 trait,trait 可以要求其他能力,不要求全部类型排列成一棵单继承树。能力关系来自明确建立的实现,而非成员恰好同名。
采用 Trait 作为能力定义对象的类型时,Priced 满足 `Priced ∈ Trait`,Trait 自身满足 `Trait ∈ Type`、`Trait ⊆ Object`。能力定义可以被其他对象引用,平台检查和保留它与实现类型的关联。实现 Priced 表示满足这份能力契约,不表示某个商品对象的直接实例类型变成 Trait。
平台候选职责包括保存 trait 定义身份、检查必需成员、检查实现的签名与关联类型,以及在调用或泛型绑定时解析选定的实现关系。默认方法可以作为候选,但默认方法存在不代表实现自动获得所有需要的状态和初始化过程。
建议分别讨论必需操作、可选默认实现和具体实例状态。两个 trait 定义同名操作时,应有明确的选择或限定机制;一个类型对同一 trait 是否允许多个实现,也需要决定如何选定,不能让导入顺序默默改变行为。
trait 可以描述“可读取”“可调用”等能力,但不能把全部开放语义概念都缩减成方法表。一个文本是否构成合适的商品说明,仍可能需要用途、语境和判断依据;实现一个操作 trait 不等于证明这些语义要求。
**待定重点:** 正式声明与实现形式、多能力组合、关联类型与常量、默认实现、冲突处理,以及静态绑定与运行时选择的边界。这里不直接采用 Rust 的借用检查、生命周期参数或 trait 实现限制。
候选声明,外部归属为 `atelier:shop.pricing`。trait 内声明所需函数签名,class 通过 implements 显式实现能力;self 暂表示当前实例:
```endorphin
trait Priced {
price: Function<() -> Number>
}
trait Named {
name: Function<() -> String>
}
class TeaOffer implements Priced, Named {
amount: Number
price: Function = () -> Number {
return self.amount
}
name: Function = () -> String {
return "Tea"
}
}
```
候选使用片段,构造器采用命名字段形式:
```endorphin
let offer: TeaOffer = TeaOffer { amount: 90 }
let amount: Number = offer.price()
let title: String = offer.name()
let capability: Trait = Priced
```
amount 为 90,title 为 `"Tea"`;capability 引用 Priced 的定义,不是一个商品。TeaOffer 同时实现两个能力,不需要把 Priced 和 Named 排成父子类。删除 implements 后,仅保留同名函数不视为自动实现;trait 作为值的 Trait 类型也是待选项。
## Code
代码结构表达声明、表达式及其组成和引用关系。它与源码文本不同:文本可以只是展示或待解析输入,代码结构则需要明确语法位置、名称绑定、类型检查状态及依赖。
Code 对象可以引用其他定义对象,组合代码仍可作为独立 atom。平台检查或重新准备对象时,可以更新准备信息,不能因此原地改写已保存的代码结构和确定依赖;修改这些内容产生新的 Code 资源对象。
Code 类型对象是 Type 的实例,并继承 Object。表达式代码对象是相应 Code 类型的实例;其求值结果可以是 Number 等另一种类型的对象。代码对象、代码类型和执行结果分别保存身份与类型关系。
平台可提供读取结构、定位子结构、创建修改后的结构、检查和准备的操作。表达式、函数定义、class 定义和由多个定义组成的代码资源可以作为这一组中的不同形式,不要求每段代码都可以直接调用。
组合后的代码仍然可以成为独立资源。代码 atom 是可独立识别和引用的单元,不要求内部不可分;同样也不要求每个词法符号都拥有独立登记条目。独立保存的粒度及嵌套成员的定位方式仍待定。
确定的可执行代码需要保留实际绑定的定义依赖。相同文字在不同绑定上下文中可能产生不同的程序含义;因此代码身份不能只凭文本看起来相同就合并。运行时引用与输入按明确契约保留其动态性。
候选一是提供通用代码类型及可检查的不同结构形式;候选二是为表达式、声明和程序组合分别提供专门类型。前者统一变换入口,后者能更早排除把表达式放到声明位置等错误。可以先确定结构约束,再选择外部类型数量,避免让“代码可操作”意味着所有结构任意拼接。
**待定重点:** 代码粒度、文本与结构的转换、子结构身份、依赖绑定保存、未检查代码与已就绪定义的表示,以及重命名和作用域保护。查看代码结构不执行其业务逻辑。
候选函数体片段,外部归属为 `atelier:shop.pricing`。quote 暂表示捕获代码结构,prepare 请求平台检查并准备,evaluate 仅用于已就绪表达式:
```endorphin
let source: String = "100 - 10"
let expression: Code<Number> = quote { 100 - 10 }
let prepared = expression.prepare()
let amount: Number = prepared.evaluate()
```
source 仍是文本;expression 是尚未执行的表达式结构;检查与准备成功后,evaluate 的预期结果为 90。失败时不能得到可用的 prepared 并继续求值,具体失败传播记法尚待选择。本方案说明代码可作为资源操作,不承诺任意文本可以立即执行。
若将表达式换为含名字的代码,quote 还必须保留其绑定上下文。只拼接字符串并不能解决作用域和资源依赖问题。Code、quote、prepare 与 evaluate 都是本例待评审的接口与记法。
## class
class 构造具有名义身份的类型对象,可以组织字段与成员函数。`class Product { ... }` 创建并命名 Product 类型对象,Product 是 Type 的实例;按 Product 创建的每个商品对象则是 Product 的实例。
class 的定义对象与实例对象都属于 Object。定义的检查与持续可引用属于 Preflight,具体实例的创建、使用、状态与保留属于 inflight。平台通过实例与定义的关联组织生命周期;一个实例结束不结束其他实例,也不自动回收仍被引用的定义对象。
平台负责理解结构、检查字段和方法关系,以及按最终构造规则建立实例。查看 Product 类定义不会取得任何商品,定义 class 也不自动创建数据库表或读取成员。
没有指定其他父类型时,Product 以 Object 为基础。显式父类型的候选写法为 `class Product: Object { ... }`;这条继承关系与 `Product ∈ Type` 的实例化关系分别保存。class 构造入口本身也有对象身份及实例类型,其具体接口尚待确定。
class 通过 trait 组合多种能力的方向已经明确;字段或状态的复用、构造顺序与方法选择仍需单独设计。“实现多个能力”不自动确定传统多重继承的全部布局和初始化语义。
**待定重点:** 构造入口的类型与调用形式、默认值、接收者、成员可见性、实例身份与可变性,以及 class 与记录的关系。
候选声明,外部归属为 `atelier:shop.data`:
```endorphin
class Product {
name: String
price: Number
}
```
候选使用片段;本方案使用 Type 表达定义资源,保留 class 的名义实例类型:
```endorphin
let definition: Type = Product
let tea: Product = Product { name: "Tea", price: 90 }
let coffee: Product = Product { name: "Coffee", price: 80 }
let amount: Number = tea.price
```
definition 指向 Product 类型对象,tea 与 coffee 是两个分别构造的 Product 实例,amount 为 90。三者都有自己的对象身份:definition 引用类型,tea 和 coffee 引用商品;构造器并未读取或创建数据库记录。
[Ref、Cell](references.md) · [类型系统](README.md) · [Function](functions.md)
+154
View File
@@ -0,0 +1,154 @@
# 7.13 Task、Stream、State、Session
Task、Stream、State 和 Session 讨论类型系统怎样组织运行实体、变化状态和跨调用的上下文。它们可以作为高级结构的成员,也可能通过已有 class 和 trait 组合实现。原生地位与操作契约需要分别决定,Agent 的类型组织单独见[下一节](agents.md)。
本页代码外部归属统一为 `atelier:shop.pricing`。除注明的 class 声明外,代码块都是独立的函数体片段。Task、Stream、Session 及其成员操作均为设计候选,使用[总览](README.md)中的示例记法。
定义和运行时实体的主定义见[Preflight 与 inflight](../../guide/05-preflight-and-inflight.md#56-定义与运行时生命周期)。实际任务、消息、会话状态和检查点属于 inflight,即使长期保存也不转为代码定义。
Task、Stream、State 和 Session 都接入 Object 模型,状态变化、活动结束与资源保留由平台分别处理。每个运行对象可以关联其他对象;组合整体与内部任务、状态不必具有相同存续范围。
Task、Stream、State 和 Session 类型对象本身属于 Type。任务 job 是某个 Task 类型的实例,任务结果则是该 Task 所约束的另一种对象;任务、结果与任务类型分别拥有身份。继承关系描述运行类型怎样接入 Object,不描述哪个任务产生了哪个结果。
| Object 类别 | 特有的生命周期职责 | 结束之后的资源关系 |
| --- | --- | --- |
| Task | 管理一次执行的等待、活动、完成及取消 | 结束后仍可保留结果和必要运行记录 |
| Stream | 管理生产、接收、结束及相应订阅关系 | 结束接收不自动回收被其他对象引用的数据 |
| State 候选或普通状态实例 | 按内容类型维护更新与快照 | 保存快照是保留相应对象内容与关系 |
| Session | 组织跨调用上下文及结束过程 | 会话结束不自动删除独立任务和长期资源 |
## Task
任务表达一次具有身份和存续过程的执行。例如批量计算商品价格可能立即结束,也可能先交付一个可观察的任务,再在后续取得最终结果。
任务候选操作包括观察状态、等待结果、请求取消,以及在明确支持时暂停和恢复。平台需要区分等待输入、正在执行、成功、失败与取消等情况;状态的最终集合、合法转换和源码形式仍待定。
候选一是普通调用对等待透明,只有显式需要管理执行时才取得任务对象;候选二是可能等待的调用都返回任务;候选三是在函数类型中区分即时交付和任务交付。前者简化常见调用,后两者让生命周期更显式,但会影响组合方式。需要与 Function 的返回类型规则一起选择。
任务身份与最终结果身份不同。同一任务可以一直保留同一身份,而执行状态持续变化。取消请求不保证外部操作已经撤销,失败也不代表所有已经发生的效果都未发生。
这属于可变运行 Object 的语义:资源 ID 指向同一个任务对象,任务状态由生命周期规则改变。需要确定历史状态时,应保存相应快照对象,不把任务 ID 当成某一时刻内容的 ID。
Preflight 可以检查任务操作与结果类型;实际等待、进度、取消响应和失败属于 inflight。恢复能力需要定义如何处理已发生的业务效果,不能由保存了一个状态字段推出任意位置都能恢复。
**待定重点:** 返回任务的形式、状态集合、等待方式、取消与超时、恢复粒度、结果保留和多次等待规则。
采用显式任务方案的候选片段,start 接收一个无参函数并建立执行任务,await 暂表示等待完成:
```endorphin
let job: Task<Number> = Task.start(() -> Number {
return 100 - 10
})
let amount: Number = await job
```
job 是一次执行,amount 才是它成功交付的 90。不能直接写 `job - 5` 来假装任务已经是数值。若执行失败,await 不交付 Number;错误传播语法另定。
另一个时点可以对仍保留的 job 调用候选操作 `job.cancel()`。这表示请求取消,不能保证一定赶在减法完成之前;任务已完成、正在取消和取消成功应有可区分的观察结果。
## Stream
流表达随时间逐步到达的多个元素,例如商品库存的持续更新。列表通常表示一组已经确定的内容;流需要说明元素何时可用、何时结束以及接收方如何跟上生产方。
平台候选操作包括订阅或取得后续元素、处理结束与失败、取消接收,以及在生产过快时表达压力。具体成员名和控制语法未定义。
至少有两种需要比较的语义:每个使用者重新开始产生一条流,或多个使用者订阅同一个正在发生的来源。前者适合可重新执行的计算,后者适合共享更新,但需要定义新订阅者能否看见过去的元素。
顺序、重复交付、丢失与重放能力需要由流契约声明。使用流不自动获得永久事件日志,也不自动保证每个元素只产生一次业务效果。重新订阅带业务修改的生产过程,可能重新触发操作,需要明确约束。
有限媒体文件与实时媒体流也应区分:保存的视频内容可以确定且有结束位置,直播则会继续到达数据。可以让两者复用元素类型和媒体能力,不必把两种生命周期混成一个隐含行为。
**待定重点:** 元素类型、有限与无限、生产与订阅范围、顺序、回放、压力处理、错误结束,以及流与 hook 的关联。hook 不因本候选而自动等同于流。
候选片段用有限来源展示组合。from 按列表顺序产生元素,map 在本例选择顺序调用,collect 等到结束后交付列表:
```endorphin
let prices: Stream<Number> = Stream.from([100, 90, 80])
let discounted: Stream<Number> = prices.map((price: Number) -> Number {
return price - 10
})
let amounts: List<Number> = await discounted.collect()
```
在完整接收且没有失败时,amounts 为 `[90, 80, 70]`。如果来源改为一直不结束的价格更新,collect 就不能按同样方式等待“全部元素”;应采用逐项消费或明确的截取范围。这个差别决定 Stream 不能仅作为延迟到达的 List 别名。
## State
实例状态表示一个运行对象在某个时刻使用的值和引用,例如结算会话当前选中的商品及优惠条件。它依附于具体实例、任务或会话;仅仅保存状态不会创建一个新的代码定义。
这一项不一定需要独立的 State 顶级类型。候选一是通过普通 class 实例和可变引用表达状态;候选二是提供统一状态对象及明确更新能力。前者复用现有结构,后者便于统一观察和恢复,但需要规定状态边界与一致性。
平台需要能够区分共享实例与独立实例。两个结算任务采用同一函数定义,不代表购物选择也共享。若明确共享状态,则需说明一次读取和更新是否看到一致的内容,以及冲突如何交给程序处理。
状态快照可以作为确定内容保留,但恢复快照不自动撤销发送过的消息或其他外部业务效果。快照若包含数据库、流或其他实例引用,也需要说明恢复的是引用关系还是目标当时的状态。
**待定重点:** 是否单独原生化、状态归属、实例可变性、共享与更新规则、快照的范围,以及恢复和业务效果的关系。
采用普通 class 表达状态的候选声明:
```endorphin
class CheckoutState {
amount: Number
}
```
候选函数体片段;本方案明确允许运行实例字段更新,let 固定实例引用:
```endorphin
let state: CheckoutState = CheckoutState { amount: 100 }
let alias: CheckoutState = state
let previous: Number = state.amount
state.amount = 90
let observed: Number = alias.amount
```
previous 仍为 100,observed 为 90。变的是该实例字段保存的目标,数值资源 100 没有变化;alias 观察同一实例。本例展示“不增加 State 类型”的方案,也提出必须确认的实例可变性规则。如果选择不可变实例,字段赋值应被拒绝,并改用新实例及显式可变引用。
若选择原生 State 候选,还可以提议用 `State<CheckoutState>` 约束受管理的状态结构:
```endorphin
class CheckoutContext {
current: State<CheckoutState>
}
```
此声明沿用前述 CheckoutState。State 的参数确定内容结构,平台额外理解更新、观察或快照等约定;这些额外能力需要逐项定义。若普通 class 与 trait 已能完整表达所需行为,则不必为了这个名称新增原生类型。
## Session
会话组织一段跨多次调用的上下文。例如一个用户连续调整商品与优惠条件,可以在同一会话内保留选择;不同用户的会话需要明确隔离。
会话与用户账号不同:用户可以同时拥有多个业务会话,会话也不自动取得创建者的全部权限。会话与任务也不同:一段会话可以包含多次已经完成或仍在运行的任务。
候选一是由应用使用普通类型管理会话,平台只提供引用与状态机制;候选二是平台提供会话身份、上下文关联和结束过程。第二种方案有利于跨调用的一致操作,但不能让所有函数默认依赖一个不可见的全局会话。
如果采用平台会话,建议让依赖它的函数类型或调用契约能明确表达所需上下文。通过参数传入与通过明确的上下文能力取得,是两种可比较的形式,尚未选定。
会话结束可以解除部分保留关系,但不自动删除它产生的全部资源、长期记忆或独立任务。结束、过期、继续使用和清理需要分别说明。
Session 的平台职责是管理一个上下文 Object 的存续。其 state、引用的 Function 和所属任务仍是其他对象,各自按有效引用与生命周期保留。关闭会话与回收这张对象子图不是同一个动作。
**待定重点:** 是否建立原生会话类型、创建与绑定方式、跨任务传播、并发访问、有效期、结束语义及权限变化。
候选片段采用本页的 CheckoutState,create 创建独立会话状态,close 结束会话:
```endorphin
let first: Session<CheckoutState> = Session.create(CheckoutState { amount: 100 })
let second: Session<CheckoutState> = Session.create(CheckoutState { amount: 80 })
first.state.amount = 90
let a: Number = first.state.amount
let b: Number = second.state.amount
first.close()
```
按本候选,a 为 90,b 为 80。会话组织状态的作用域;状态仍由普通类型表达,结束 first 不结束 second。关闭后是否允许读取已保存快照,与是否允许继续发起会话内调用,是需要分别定义的行为。
如果选择不提供原生 Session,应用可以自己管理 CheckoutState 的引用与存续。两种方案的差别是平台是否理解会话边界、负责传播与结束过程,不只是有没有一个叫 Session 的 class。
## 不必立即新增的类型
工具关联可以先表达为函数资源及其描述;记忆内容可以采用文本、媒体、结构化值与引用;检查点可以是一份具备明确恢复含义的状态记录。是否分别新增 Tool、Memory、Checkpoint 顶级类型,应由独立操作和检查需求决定。
可观察、可取消、可恢复和可呈现也可以作为候选 trait 能力组合。它们与具体实例状态的存储不是同一件事,实现某种能力必须满足相应操作契约,不能只提供同名成员。
[Function](functions.md) · [类型系统](README.md) · [Agent、agent](agents.md)
+142
View File
@@ -0,0 +1,142 @@
# 7.12 Function
Function 是平台原生支持的可调用代码类型。它为函数定义建立自身的类型身份和可扩展行为,能够成为 class 成员、容器元素、代码依赖或 Agent 工具。平台理解它的调用签名、实例状态和生命周期,用户在这一基础上定义更高级的函数结构。
Function 以 Object 为共同基础。函数定义、按定义建立的函数实例、实际调用及其运行状态都纳入对象体系,但分别具有自己的身份和生命周期。平台认识定义对象的可调用能力,再按获准的调用契约执行函数体;持有一个 Object 不自动启动调用。
Function 类型对象是 Type 的实例,并继承 Object;discountedPrice 这份可调用对象是 Function 的实例。扩展类型 CountingFunction 同样是 Type 的实例,在继承线上继承 Function。函数对象的直接实例类型与调用结果的类型分别检查。
本页展示候选语法供比较。代码外部归属统一为 `atelier:shop.pricing`,调用片段位于函数体内;各例声明可在相应片段中使用。Function 的方向已经明确,但本页的签名记法、实例操作和生命周期成员尚未定稿,状态见[规范状态](../../appendices/specification-status.md#顶级类型讨论)。
## Function
候选 A 将函数写成有类型的定义:
```endorphin
discountedPrice: Function = (price: Number, discount: Number) -> Number {
return price - discount
}
```
discountedPrice 后面的 Function 指定这份定义的自身类型;右侧签名则约束调用方式,其中箭头后的 Number 是结果约束。本候选也允许完整标注为 `Function<(Number, Number) -> Number>`。Function 决定这是什么结构、如何扩展,签名参数帮助检查这个结构怎样被使用;尖括号记法仍待选。
调用片段:
```endorphin
let amount: Number = discountedPrice(100, 10)
let pricing: Function<(Number, Number) -> Number> = discountedPrice
let another: Number = pricing(80, 7)
```
amount 为 90,another 为 73。pricing 保存函数资源,amount 保存调用结果;二者类型不同。引用 discountedPrice 不会额外执行一次定价。
候选 B 将具体函数类型放在声明开头。下面是同一个定义的替代写法,不与候选 A 同时声明:
```endorphin
Function discountedPrice(price: Number, discount: Number) -> Number {
return price - discount
}
```
| 比较点 | 候选 A:名称后标注类型 | 候选 B:类型开头 |
| --- | --- | --- |
| 普通函数 | `discountedPrice: Function = ...` | `Function discountedPrice(...) ...` |
| 自定义函数类型 | 把 Function 换成具体类型 | 把开头的 Function 换成具体类型 |
| 与普通绑定的关系 | 与名称、类型、值的顺序一致 | 函数定义具有专门的声明外形 |
| 要继续确定 | 定义绑定与局部变量怎样区分 | 参数化函数类型怎样保持可读 |
以下例子采用候选 A,保留名称、类型、对象构造三者的对应位置。函数构造必须能够表达具体函数自身类型;仅标注参数与返回类型不足以区分 Function 和其扩展类型。是否提供简写形式仍待定义。
## Function 作为成员与依赖
在前述 discountedPrice 声明之外,增加接受函数的候选声明:
```endorphin
applyRule: Function = (
rule: Function<(Number, Number) -> Number>,
price: Number,
discount: Number
) -> Number {
return rule(price, discount)
}
```
调用片段 `let amount = applyRule(discountedPrice, 100, 10)` 的预期结果为 90。参数传入的是函数资源本身,没有先执行它。Preflight 应检查 rule 的调用签名;接收文本的函数不能仅因也可调用就代入。
Function 同样可以组成其他类型。以下候选声明把定价行为纳入一个有名义身份的结构:
```endorphin
class RuleSet {
name: String
pricing: Function<(Number, Number) -> Number>
}
```
```endorphin
let rules: RuleSet = RuleSet { name: "标准优惠", pricing: discountedPrice }
let amount: Number = rules.pricing(100, 10)
```
pricing 是结构成员,discountedPrice 是它保存的函数依赖。按当前候选调用得到 90;保存 RuleSet 时,需要保留 pricing 对应的函数资源及其确定依赖。若函数捕获环境,还需要说明环境的成员类型、身份与共享方式,不能由函数名或者调用结果类型替代这些规则。
## CountingFunction
CountingFunction 展示继承原生 Function 并增加结构与生命周期逻辑的候选。它为每个显式创建的实例记录调用次数。class 后的冒号暂表示扩展平台原生类型;beforeCall 暂作为平台约定的调用前入口,self 表示当前函数实例。
```endorphin
class CountingFunction: Function {
calls: Number = 0
beforeCall: Function = () -> Unit {
self.calls = self.calls + 1
return ()
}
}
countedPrice: CountingFunction = (price: Number, discount: Number) -> Number {
return price - discount
}
```
countedPrice 的自身类型是 CountingFunction,返回类型仍然是 Number。它同时使用原生调用机制、用户写的业务函数体和扩展类型的生命周期逻辑。beforeCall 是本候选的特殊接入点,不是给任何 class 添加同名函数就自动生效。
CountingFunction 经由 Function 接入 Object 基础,并增加自己的实例成员与生命周期逻辑。平台管理共同的对象身份和引用图,再根据具体函数类型执行 beforeCall 等扩展动作。Object 的存在不意味着所有对象共享这组调用回调。
候选使用片段;instance 建立独立状态,close 结束该实例并禁止后续新调用:
```endorphin
let first = countedPrice.instance()
let second = countedPrice.instance()
let a: Number = first(100, 10)
let b: Number = first(80, 7)
let firstCount: Number = first.calls
let secondCount: Number = second.calls
first.close()
```
按本候选顺序执行,a 为 90,b 为 73,firstCount 为 2,secondCount 为 0。函数定义一直可被引用,first 的实例状态跨两次调用存续,second 拥有自己的状态。关闭 first 不删除定义,也不关闭 second。这就是比一次函数调用更长的生命周期。
本例提议显式实例化,避免所有引用者无意共享 calls。另一个候选是通过明确的会话绑定自动取得函数实例,可以减少 `.instance()`,但需要定义会话范围和共享规则。二者都不能让同一函数定义的所有使用者默认共享一个隐藏计数器。
这个顺序例子未定义并发计数、beforeCall 失败、重入、关闭时仍有调用等行为。beforeCall 若被调用后业务失败,当前候选记录的是调用尝试次数;若要只统计成功次数,应增加明确的成功回调,而不能悄悄改变含义。instance、close、beforeCall 和 Unit 都仍是候选接口。
## 平台需要保留的调用契约
| Object 类别 | 平台管理的生命周期 | 必须保留的关系 |
| --- | --- | --- |
| Function 定义对象 | 创建、检查、准备及持续可引用 | 函数体与确定绑定的定义依赖 |
| 函数实例对象 | 建立环境、使用、状态存续和结束 | 所用定义及该实例需要的对象 |
| 调用活动与相关运行对象 | 输入绑定、执行、等待、完成或失败 | 本次执行需要的输入、定义及恢复状态 |
这些对象可以以独立资源 ID 登记,也可以作为组合运行结构的一部分;具体登记粒度仍待定义。运行结束后,结果、状态或历史记录若仍被有效保留根引用,就继续存续。
Preflight 检查函数自身类型、签名、已知依赖与扩展接入点;inflight 执行业务逻辑并维护实例和调用状态。查看定义不启动调用,普通函数不自动是纯函数,增加缓存或重试也不能任意跳过或重复业务效果。
暂停任务需要保留对应函数定义、确定依赖和恢复状态。namespace 改指新定义,不自动把旧实例迁移过去。实例更新需要规定状态兼容及迁移,不能由函数名相同推导。
Function 的原生扩展还可以与 trait 能力组合:例如某种函数实现可取消、可观察能力。是否另设通用“可调用”trait,让其他对象显式接入函数调用,是一个独立选择;它不取消 Function 本身的原生地位。
**待定重点:** 选择声明语法、定义与实例的类型关系、生命周期接入点、捕获环境、可调用次数、实例共享及错误行为。泛型和遗传算法可以进一步选择或组合函数资源,但本页不确定完整搜索与优化机制。
[Type、Trait、Code、class](definitions.md) · [类型系统](README.md) · [Task、Stream、State、Session](execution.md)
+125
View File
@@ -0,0 +1,125 @@
# 7.10 Ref、Cell
引用连接代码、基础内容和运行实体。这里讨论确定资源引用与可变目标引用是否需要独立类型,以及程序持有引用时可以依赖哪些行为。正式类型名、构造和赋值语法仍待确定,已有变量模型见[表达式与绑定](../../guide/08-expressions-and-bindings.md#86-变量与资源引用)。
Ref 和 Cell 自身也是 Object 候选,目标则是它们关联的另一个对象。引用对象的身份、目标对象的身份和可变位置当前保存的目标需要分别记录;平台据此维护[Object 的资源图与生命周期](README.md#objectatom-与资源-id)。
引用对象具有自己的直接实例类型,例如 Ref<Number> 或 Cell<Number>;这些具体类型对象属于 Type,并接入 Object 的继承体系。引用所保存的目标不因此成为它的父类型;目标关联、实例类型关联与继承关联分别处理。
## 资源身份与命名入口
资源 atom 通过独立 ID 识别。workspace 承担归属和管理,namespace 为资源建立名字与组织视图。多个 namespace 可以通过各自的入口引用同一资源;入口名称和路径不构成该资源的底层身份。
atom 对应可独立引用的 Object 单元。这个单元可以是简单内容、定义、组合对象或运行实例;其 ID 固定目标身份,目标内容是否可以变化仍由具体对象类型决定。
资源 ID 是平台解析的逻辑身份,不要求指向固定机器的内存地址。调用方保存对确定资源的引用后,名称变化不应让这个引用自行改指另一个资源。名称解析何时建立绑定、源码如何保存绑定信息,以及导出后如何保留关系仍需定义。
## Ref
确定资源引用用于指向某个明确的内容、定义或运行实体。例如结算程序依赖一份已保存的定价函数,保存的是该函数的确定身份;定价 namespace 后来改用新实现,不自动改变原结算程序的依赖。
Ref 对象的准备包括解析并核对目标类型,使用包括获准访问目标能力,存续包括维护相应保留关系。以 Object 标注持有 Ref,仍引用这个 Ref 对象,不隐式改成其目标;透明引用方案下何时解引用需有明确规则。
平台承担目标解析、适用类型检查和有效引用关系的维护。引用某个函数不自动调用它,引用 class 或 Agent 定义不自动产生实例。访问仍受权限和可用条件约束,持有 ID 不直接提供读取或执行权。
存在两种表达方案:把确定引用作为普通值使用时的透明基础机制,或允许用户显式声明一种带目标类型约束的引用。透明机制更接近日常使用资源的体验;显式类型便于区分“引用本身”与“访问得到的值”,但需要规定解引用、参数传递和推断。可以同时提供透明的常见操作与必要时显式操作引用的能力,具体规则待定。
对确定内容和定义,引用身份固定也固定该份内容;对数据库服务、任务等运行实体,固定身份只说明还是同一个对象,不承诺其状态保持不变。需要历史内容时,应引用明确的内容或快照,而非把服务身份误作快照身份。
**待定重点:** 是否暴露独立引用类型、目标类型约束、访问与解引用形式、定义引用与实例引用的表示、ID 的可见形式,以及不可用目标的处理。
候选代码先声明被引用的函数,外部归属为 `atelier:shop.pricing`:
```endorphin
discountedPrice: Function = (price: Number, discount: Number) -> Number {
return price - discount
}
```
调用方的外部归属为 `market:shop.checkout`,假设目标已授权、可见且没有同名冲突:
```endorphin
use atelier:shop.pricing
checkoutPrice: Function = () -> Number {
let pricing: Ref<Function<(Number, Number) -> Number>> = &discountedPrice
return pricing(100, 10)
}
```
本候选用 `&` 取得确定引用,Ref 标明目标类型,并允许对函数引用直接调用。Function 内的箭头描述参数和结果约束;这是一套候选类型记法。保存 checkoutPrice 时,discountedPrice 绑定到当时选定的函数资源。预期返回 90;以后命名入口改指另一份函数,不改变这份已保存程序的确定依赖。
若选择透明引用方案,可以把函数体写为 `return discountedPrice(100, 10)`,由平台保留相同的确定绑定。需要选择的是引用是否显式书写,而不是让名称更新偷偷改变旧程序。
## Cell
Cell 是显式可变引用位置的候选类型,可以成为其他结构的成员。普通变量是否需要写出这样的类型仍另行讨论。价格变量先指向数值 100,再指向数值 90;变化的是引用目标,100 和 90 本身都仍是确定的数值内容。
平台按 Cell 的生命周期建立位置、检查目标更新并维护当前引用关系。同一个 Cell 对象可以持续存在,内部目标发生变化;它的旧目标是否仍需保留,由其他有效引用与历史保留策略决定。关闭某项运行活动不自动删除仍被其他对象引用的 Cell。
平台需要检查新目标符合引用允许的类型和作用域,并使更新可以被后续合法使用观察到。重新绑定变量与原地修改被引用内容分别处理;前者不赋予后者能力。
最重要的选择是“共享目标”和“共享引用位置”的区别。两个变量可以最初都指向同一图片,但各自重新绑定;它们也可能显式共享同一个可变引用位置,从而观察到同一次目标更新。建议默认说明普通变量各自保存目标,把共享引用位置作为必须明确表达的候选能力。
类型约束同样需要区分“指向实现某 trait 的某个资源”和“永远指向同一个具体名义类型的资源”。能否更换具体类型,应由引用声明和使用规则决定,不能由当前值恰好可以调用某个方法决定。
**待定重点:** 声明与赋值形式、let 是否可重绑、共享位置的表达、并发更新的一致性、目标类型变化、引用自身的保存与恢复。
候选函数体片段,外部归属为 `atelier:shop.pricing`。本方案用 var 声明可重绑变量,let 保存当前目标;这些关键字分工尚未定稿:
```endorphin
var price: Number = 100
let previous: Number = price
price = 90
```
随后 price 指向 90,previous 仍指向 100。平台没有把数值资源 100 改成 90。若要共享同一可变位置,可以另采用下面的显式 Cell 候选;此片段与上例独立:
```endorphin
let shared: Cell<Number> = Cell(100)
let alias: Cell<Number> = shared
shared.set(90)
let observed: Number = alias.get()
```
本候选中 observed 为 90,因为 alias 与 shared 指向同一个可变位置。Cell、get 和 set 是待选的表达方式,不能从普通赋值自动推导这种共享行为;并发读写契约也不由这个顺序例子确定。
## 修改、采用与移除的行为对照
以下以定价函数与结算程序说明命名入口和确定引用的关系;表内不是源码或平台 API。
| 行为 | 对命名入口的影响 | 对原结算程序的影响 |
| --- | --- | --- |
| 保存新的定价实现 | 可以暂不改变入口 | 继续引用原函数 |
| 将入口改为新实现 | 后续按该入口查找会找到新目标 | 已保存的确定引用保持原目标 |
| 从 namespace 移除原入口 | 该入口不再列出资源 | 仍保留的依赖可以继续解析原资源 |
| 让结算程序采用新实现 | 不要求修改其他入口 | 保存采用新引用关系的程序资源 |
定义资源的确定身份包括其确定绑定的定义依赖;绑定选择发生变化时不能悄悄改写旧程序。运行输入、可变引用和外部状态则按各自契约使用,不因定义固定就全部被冻结。
## 引用与回收
已确认的保留原则是可达性:从仍需保留的目录入口、程序、运行任务或历史记录等有效根出发,可以沿保留引用到达的资源不能回收。这里列出的根种类用于解释原则,哪些记录默认成为根、保存多久仍待定义。
单纯统计入向引用不足以决定回收。两个资源可以互相引用,却不再被任何保留根到达;这种循环需要识别。相反,从 namespace 移除某个函数入口后,只要另一个保留程序仍依赖它,就不能因为目录中看不见而清理它。
待定的实现契约包括:建立引用与回收之间的一致性、历史记录和来源关系是否保持内容、仅保存 ID 文字是否构成保留引用,以及不可达后的宽限期。建议区分影响程序运行的保留引用与只用于说明来源的记录,避免所有历史描述都无期限阻止清理;这一分工尚未确认。
释放当前物理内存中的准备结果,不等于删除资源。平台可以在仍保留资源身份及必要内容的前提下,按需再次准备它。具体存储和回收算法不由本页指定。
以前面的程序为例,保留关系如下;这是资源图示意,不是代码:
```text
保留的 checkoutPrice → 原 discountedPrice
namespace 当前入口 → 新 discountedPrice
```
两份定价函数都可能仍需保留。即使移除旧函数的全部目录入口,第一条路径仍保护它;只有不再被有效根到达时,才进入可清理候选。这个判断不需要用户手动释放内存指针。
## 权限与管理关系
移除命名入口不等于撤销既有调用授权。资源仍然存在,也不意味着任何曾见过其 ID 的用户永久拥有访问权。资源保留、入口可见性和授权变化需要分别处理。
workspace 和 namespace 属于管理模型,不在此新增 Workspace 或 Namespace 原生资源类型。资源跨 namespace 或跨 workspace 被引用时,命名关系不自动改变它的管理归属;跨 workspace 授权和资源保留责任仍需完整规则。
[Tuple、record、List、Map、Set、Option、Result](collections.md) · [类型系统](README.md) · [Type、Trait、Code、class](definitions.md)
+131
View File
@@ -0,0 +1,131 @@
# 7.8 Bool、Number、String、Unit、Null
本页讨论 Bool、Number、String,以及 Unit、Null 候选在语言类型系统中的地位。它们可以约束 class 字段、变量和结构成员,也参与表达式及容器组合。各项的正式规则按[讨论状态](../../appendices/specification-status.md#顶级类型讨论)处理,代码采用[总览](README.md)中的候选记法。
基础值可以成为独立资源,也可以作为参数、局部计算结果或复合值的成员。给资源确定身份不要求每次计算都登记一个 namespace 名称;临时值进入可独立引用资源体系的具体形式待定。
本页示例的外部归属为 `atelier:shop.pricing`。标注为声明的例子保存为定义;其余代码块是彼此独立的函数体片段,不能拼成一份顶层程序。Bool、Unit、Null、Option 及相关操作均为本页候选名。
本页各项都是 Object 的具体类型候选,采用[Object](README.md#object)的统一对象与资源模型。平台按类型保存内容、准备表示并提供相应操作;基础内容对象不可原地改写,计算或文本修改产生新内容对象。被保留结构引用的内容继续存续,结束一次计算不清除这些对象。
数值 90 是 Number 的实例,Number 类型对象是 Type 的实例,并继承 Object。Bool、String 等同样区分具体值与类型对象:值保存内容,类型对象规定结构与操作,二者都可以作为资源被引用。
| Object 类别 | 平台管理的生命周期 | 对组合结构的影响 |
| --- | --- | --- |
| Bool、Number | 建立确定内容、参与相应运算、保留有效引用所需内容 | 改绑字段或变量不改写旧值对象 |
| String | 准备文字表示、执行文本操作、按引用保留内容 | 拼接得到新对象,原结构仍可引用原文本 |
| Unit、Null 候选 | 按选定的单值或空值语义建立对象并维护引用 | 原生地位与去重规则待定,仍使用共同对象模型 |
## Bool
布尔用于表达确定的真假结果,承担条件判断和逻辑组合。商品是否满足优惠条件可以得到布尔值;读取优惠条件失败则是执行失败,不能直接解释为“不满足优惠条件”。
Bool 对象可以作为成员被其他对象引用,也可以以 Object 标注持有;后者保留原来的具体类型,不能自动把其他对象转换成真假。
建议平台提供真假表示、逻辑运算、相等判断,以及把布尔结果交给控制流的能力。Preflight 检查条件位置所需的类型;inflight 使用实际输入完成判断。真假字面量、逻辑运算符和短路求值规则仍需与文法一起确定。
候选一是要求条件明确使用布尔;候选二是允许数值、空列表等按规则转换为真假。前者使条件含义直接,后者减少显式转换但需要逐类规定规则。建议先采用明确布尔条件,不从数字零、空文本或资源未就绪推导真假。
候选结构声明:
```endorphin
class OfferCondition {
enabled: Bool
}
```
```endorphin
let first: OfferCondition = OfferCondition { enabled: 100 >= 100 }
let second: OfferCondition = OfferCondition { enabled: 90 >= 100 }
```
按本例候选规则,first.enabled 为 true,second.enabled 为 false。enabled 的字段类型约束所有实例;把 `"开启"` 写入这个字段不能仅凭文本意思近似就通过检查。`>=`、真假字面量与类型名一并等待确认。
**待定重点:** 正式类型名和字面量;逻辑运算的求值顺序;是否允许显式或隐式转换;带未知信息的判断是否应使用可选值或其他结果类型。
## Number
Number 表达价格、数量、比例、坐标分量和计算结果。整数、小数与可扩展的大数采用同一数值类型;浮点属于表示与精度的选择,不要求使用者另选机器类型。
Number 对象具有确定数值内容。对象身份与数值相等是两个维度:两份登记资源是否复用同一对象,由身份与去重规则决定;内容比较按数值规则判断,不能直接用资源 ID 代替。
平台承担数值保存、基本算术、比较与显示。定价函数接受 100 和 10,按减法得到 90;这是按现有规则手算的说明。能够保存很大的数,不代表能精确保存任意实数,也不决定除法和超越函数的精度。
需要区分数值内容、显示格式和业务约束。价格显示为两位小数不自动改变底层数值;价格禁止为负数可以由业务类型或显式约束表达。数量为整数的要求可以作为约束讨论,无须据此恢复固定机器位宽类型。
| 算术候选 | 对价格计算的影响 | 需要明确的边界 |
| --- | --- | --- |
| 对可精确表达的结果保持精确,其他运算明确要求精度策略 | 容易解释有限小数、整数和部分比例的计算 | 非终止小数、精度策略的传递及资源成本 |
| 使用统一默认精度和舍入规则 | 常见运算形式一致 | 默认精度如何选择、结果是否依计算次序改变 |
| 由数值或计算上下文携带精度要求 | 不同用途可选择精度 | 上下文作用域、组合时的精度冲突与可重复性 |
建议优先定义相等、比较、四则运算、除零和舍入,再确定更完整的数学能力。Preflight 可以检查已知操作与约束,运行输入造成的非法算术由 inflight 表达,不能把失败转换为零。
候选使用片段:
```endorphin
let quantity: Number = 3
let unitPrice: Number = 12.5
let total: Number = quantity * unitPrice
let largeCount: Number = 1000000000000000000000000
let ratio: Number = 1 / 3
```
quantity、unitPrice 和 largeCount 使用同一个类型。采用“有限小数可精确表达”的候选时,total 为 37.5;ratio 则迫使设计明确采用精确比例、指定精度还是默认舍入,不能把某个小数输出写成已确认结果。这里正好可以比较三种算术方案。
**待定重点:** 精度与舍入、除法、无穷与非数等特殊值、相等性、计算成本限制,以及数值和文本之间的转换。任何候选都保持统一数值类别的既定方向。
## String
String 表达商品名称、描述、提示内容和源码的文字展示;Text 是界面组件。一个文本值可以包含源码文字,但仅凭内容看起来像代码,不会成为已检查的代码定义。
平台可提供拼接、比较、切片、查找,以及文本的导入与导出。具体成员名尚未确定,外部编码由平台处理。修改文本产生新内容,变量按需要改指新结果,以保持基础常量模型。
“长度”和“第一个字符”需要明确计量单位。按字节、Unicode 码点或用户看到的字符单位计数,会影响商品名截断、选择和光标位置。候选方案可以为不同操作指定单位,或提供明确命名的多种操作;不宜让同一个操作根据输入编码改变含义。
原样相等、规范化后相等以及忽略大小写比较也需要分别说明。索引搜索可以支持宽松匹配,但不能自动改变资源内容或语言的相等性规则。
候选使用片段;本例暂用 concat 拼接,slice 采用从零开始、左闭右开的字符区间:
```endorphin
let name: String = "Tea"
let title: String = name.concat(" sale")
let prefix: String = title.slice(0, 3)
```
title 为 `"Tea sale"`,prefix 为 `"Tea"`;name 仍为 `"Tea"`。换成组合字符或 emoji 后,需要先确定字符单位,才能给 slice 相同的解释。concat 和 slice 是待选操作名,不是现有标准库承诺。
**待定重点:** Unicode 与规范化策略、索引单位、切片边界、比较规则、编码失败和字面量转义。Preflight 检查字面量和静态类型,动态内容的切片与转换失败属于 inflight。
## Unit、Null
Unit 候选是只有一个值的类型,可用于不携带额外字段内容的结构成员。它提供统一的单值结构,是否与空 Tuple 等价、是否需要独立原生类型,仍需决定。
Null 候选用于明确表达一个空值。是否允许它进入其他类型、怎样表达可空字段、能否隐式转换,是单独的类型兼容问题。Null 的存在不自动让 Number 或用户 class 都接受 null。
候选结构声明;Unit 暂用 `()` 构造,Option 沿用[Option、Result](collections.md#optionresult)中的候选:
```endorphin
class DiscountMarker {
marker: Unit
amount: Option<Number>
}
```
候选构造片段:
```endorphin
let missing: DiscountMarker = DiscountMarker { marker: (), amount: none }
let zero: DiscountMarker = DiscountMarker { marker: (), amount: some(0) }
let empty: Null = null
```
missing 和 zero 的 marker 具有相同的 Unit 值,但 amount 的结构不同:none 没有数值成员,some(0) 则携带明确的数值 0。empty 是 Null 候选的值;它不能未经类型规则允许就替代 DiscountMarker 或 Number。这里讨论的是结构成员与类型兼容,尚未确定 Unit、Null 必须同时存在。
**待定重点:** Unit 与空 Tuple 的关系、Null 是否需要原生化、可空成员的表达方式,以及相等和转换规则。
## 本页评审入口
Number 的统一类别已经确定,可优先比较精度方案。Bool、Unit、Null 的原生地位可以分别决定;它们怎样组成字段和容器,以及类型之间是否允许转换,应与具体操作一起评审。
[类型系统](README.md) · [Tuple、record、List、Map、Set、Option、Result](collections.md) · [规范状态](../../appendices/specification-status.md#顶级类型讨论)
+12 -6
View File
@@ -1,8 +1,10 @@
# 7. 资源、类型与类
Endorphin 的资源模型从基础常量值开始:数值、文本以及图片、视频、音频和 GIS 数据等内容由平台统一保存和解释。变量保存对资源的引用;class 与 agent 在这些基础上组织更高级的结构。
Endorphin 采用一切皆对象的模型。Object 是类型继承关系的根,Type 是类型对象的实例类型。Object 是 Type 的实例,Type 是自己的实例,并在继承线上继承 Object;Object 没有父类型。数值、文本、图片、代码、函数、类型定义及运行实例都接入这套闭环,平台按类型管理其生命周期。
类型描述资源或值的结构及其允许的用法。类型标注用于字段、函数参数和返回值,使不同应用部分能够依据同一声明理解数据。
资源 atom 是对象可独立识别、保存和引用的单元,资源 ID 将这些单元连接成引用图。实例化、继承、成员及代码依赖在图中保存为不同含义的关联。class 与 agent 构造入口自身也是对象,用于组织具体类型及高级结构;workspace 和 namespace 提供资源归属与命名管理。
类型描述资源或值的结构及其允许的用法。类型系统约束字段、变量、容器元素、引用目标和定义资源,并通过明确的能力关系组织 class、Function 和 agent 等高级结构;函数签名也使用这套类型规则。
## 7.1 类型标注
@@ -48,7 +50,7 @@ name: String
这里的“指向”表达语言语义,不要求开发者处理裸内存地址、手动分配或释放。变量改变引用目标与修改基础常量内容是不同操作,详见[变量与资源引用](08-expressions-and-bindings.md#86-变量与资源引用)。
资源需要独立保存、分享或再次引用时,纳入用户与 namespace 的归属和检索体系。namespace 中资源的登记形式、资源成员定位和实例标识待定;临时值不因此自动获得永久名称。
资源需要独立保存、分享或再次引用时,以独立 ID 识别,由 workspace 管理归属、namespace 提供命名与检索。一个资源可以有多个命名入口;移除入口不清除仍被保留程序引用的资源。具体登记形式与实例标识待定,临时值不因此自动获得永久名称,详见[资源引用](07-top-level-types/references.md)。
## 7.2 class 声明
@@ -69,6 +71,8 @@ class Product {
`Product` 表示一个声明的类型;具有 Product 类型并满足其字段约束的值,才包含本次业务数据。仅有相同字段不自动使其他类型的值成为 Product。
Product 类型对象是 Type 的实例,商品对象是 Product 的实例;Product 在继承线上以 Object 为基础。引用 Product 不创建商品对象,商品与类型定义也不共享同一个资源身份。字段内容可以继续引用其他对象,其保留关系按对象图处理。
类声明本身不取得某件商品,也不指定数据库、表或连接。通过类型取得数据的用法在[数据读取](10-data-access.md)中说明;构造、方法与默认值属于独立的类型规则。
## 7.4 字段访问
@@ -94,7 +98,7 @@ Preflight 理解类和字段声明,检查字段访问、函数参数与返回
Endorphin 不采用仅依据成员结构判断兼容的结构类型规则。用户声明的类型按其声明身份区分;字段或方法相同,不自动建立类型兼容或能力实现关系。
类型声明通过所属 namespace 与声明定位。引用同一个声明不创建新类型;不同声明不能仅凭名称或成员相同被认定为同一类型。
类型声明可以通过 namespace 与声明名查找,绑定后的引用指向声明资源的独立身份。引用同一个声明不创建新类型;不同声明不能仅凭名称或成员相同被认定为同一类型。
代码归属:`atelier:shop.data`。沿用本章 Product 声明,并增加以下类声明:
@@ -114,6 +118,8 @@ ListedProduct 值 → 接收 Product 的参数:不能仅凭字段相同通过
构造某个声明类型的值时仍须检查字段及其类型;这类检查不等于允许不同类型按结构互换。类型推断也不要求结构兼容,具体推断规则仍待定义。
继承、接口或协议关系、显式能力实现及类型转换的规则另行定义,见[规范状态](../appendices/specification-status.md#声明与类型)。本节不增加相应关键字或写法。
类型可以显式组合多个 trait 能力,不要求单一的树形继承结构;具体声明、实现及转换规则仍需评审。候选代码见[Type、Trait、Code、class](07-top-level-types/definitions.md),确定程度见[规范状态](../appendices/specification-status.md#声明与类型)。
[上一章:词法结构](06-lexical-structure.md) · [下一章:表达式与绑定](08-expressions-and-bindings.md) · [目录](../README.md)
Object 的共同基础允许以统一的对象位置保存不同具体类型,但不会消除具体名义身份。以 Object 持有 Product 对象,不能据此将它当作 ListedProduct 使用;数值、调用等专门操作仍依赖相应类型或显式能力。
[上一章:词法结构](06-lexical-structure.md) · [继续第 7 章:类型系统](07-top-level-types/README.md) · [下一章:表达式与绑定](08-expressions-and-bindings.md) · [目录](../README.md)
+2 -2
View File
@@ -87,6 +87,6 @@ inflight 必须在结果可用后使用它,不能将未就绪状态替换为
变量的创建、使用和引用更新属于 inflight。类型与作用域的准备属于 Preflight;变量或实例不再需要时的回收,以及保存后如何删除,见[生命周期](05-preflight-and-inflight.md#56-定义与运行时生命周期)。
可变变量的声明关键字、重新赋值、引用类型和 let 的可重绑性,见[规范状态](../appendices/specification-status.md#基础资源与变量)。本节确定引用模型,不补写尚未确认的赋值产生式。
可变变量的声明与重新赋值写法、引用类型和 let 的可重绑性尚未定义,其状态记录在[基础资源与变量](../appendices/specification-status.md#基础资源与变量)。
[上一章:资源、类型与类](07-types-and-classes.md) · [下一章:函数与调用](09-functions-and-calls.md) · [目录](../README.md)
[上一章:资源、类型与类](07-types-and-classes.md) · [第 7 章续篇:类型系统](07-top-level-types/README.md) · [下一章:函数与调用](09-functions-and-calls.md) · [目录](../README.md)
+3 -1
View File
@@ -2,6 +2,8 @@
函数定义可调用的逻辑,包括名称、输入参数、结果类型和函数体。调用表达式提供输入,并取得函数定义的结果。
discountedPrice 是 Function 的实例,Function 类型对象是 Type 的实例并继承 Object。以下采用 function 构造记法的候选简写说明基本调用;具体函数类型的构造必须另有明确的类型位置。自身类型标注及生命周期扩展示例见[Function](07-top-level-types/functions.md)。
## 9.1 函数声明
代码归属:`atelier:shop.pricing`。
@@ -16,7 +18,7 @@ function discountedPrice(price: Number, discount: Number): Number {
| 部分 | 含义 |
| --- | --- |
| `function` | 函数声明关键字 |
| `function` | 函数对象构造的候选记法 |
| `discountedPrice` | 函数名 |
| `price: Number, discount: Number` | 两个输入参数及其类型 |
| 参数列表后的 `: Number` | 返回类型 |
+1 -1
View File
@@ -57,7 +57,7 @@ Preflight 理解结构、引用和成员调用的类型关系,inflight 取得
## 10.5 一次读取与持续结果
本节 get 提案按一次读取说明。持续跟随数据变化与一次读取具有不同的可观察行为;是否使用不同表达式或结果类型仍未定义。
本节 get 提案按一次读取说明,不自动建立持续订阅。客户端可以为平台对象准备本地副本,并通过持续关联同步后续变化;这一方向见[跨端对象与同步](11-resource-access-and-presentation.md#117-跨端对象与同步)。一次读取与持续关联的源码形式、结果类型及建立方式仍未定义。
UI 可以直接使用成功取得的类型化字段展示内容,跨端通信由平台承担,不要求应用自行解析响应或恢复对象类型。加载、缺失、失败与后续更新仍需要对应的可观察状态;具体访问和呈现关系见[资源访问与呈现](11-resource-access-and-presentation.md)。
+65 -2
View File
@@ -2,7 +2,7 @@
客户端是 Endorphin 资源的查看与运行环境。它可以访问获准查看的 namespace、函数、类、agent、基础内容和结果值,并根据当前资源的类型及访问状态选择呈现方式。
界面由普通函数返回的可渲染值表达,不使用独立的 scene 声明或 render 块。本章定义资源定位、函数查看、调用与结果呈现之间的关系;顶级类型及其契约仍待定义,见[规范状态](../appendices/specification-status.md#资源访问与呈现)。
界面由普通函数返回的可渲染值表达,不使用独立的 scene 声明或 render 块。本章定义资源定位、函数查看、调用、结果呈现及跨端对象关联之间的关系;完整顶级类型集合及呈现契约仍待定义,见[规范状态](../appendices/specification-status.md#资源访问与呈现)。
## 11.1 资源定位与访问
@@ -98,12 +98,75 @@ namespace:atelier:shop.data
一次调用与持续结果的区别见[数据读取](10-data-access.md#105-一次读取与持续结果)。自动更新的范围、业务修改的重复执行规则及取消行为仍待定义;依赖关系不自动授权系统重复执行所有相关函数。
客户端通过本地对象使用远程数据时,其与平台对象的身份关联、数据传递及后续同步见[跨端对象与同步](#117-跨端对象与同步)。hook 可以参与更新关联,但不因此替代对象身份或数据存储。
## 11.6 按类型呈现的边界
按资源类型选择处理方式是客户端的呈现方向。基础数值、文本、媒体与 GIS 类别及其格式归一化见[资源、类型与类](07-types-and-classes.md);agent 的使用语义见[Agent](13-agents.md)。完整顶级类型名称、继承或协议关系,以及不同类型对应的展示契约,统一保留在[规范状态](../appendices/specification-status.md#资源访问与呈现)中。
按资源类型选择处理方式是客户端的呈现方向。基础数值、文本、媒体与 GIS 类别及其格式归一化见[资源、类型与类](07-types-and-classes.md);agent 的使用语义见[Agent](13-agents.md)。顶级类型的候选操作与代码见[逐项设计](07-top-level-types/README.md);完整类型名称、能力组合和展示契约的确定程度统一记录在[规范状态](../appendices/specification-status.md#资源访问与呈现)中。
平台不能仅凭对象字段或方法的结构认定其属于可渲染类型或实现了展示能力。类型身份与兼容规则见[类型与类](07-types-and-classes.md#76-类型身份与兼容);具体展示能力关系仍待定义。
本章不规定普通对象必须继承界面类型,也不指定数据查看器、媒体播放器或代码查看器的实现。官方 UI 组件的现有效果提案见[UI 组件](12-ui-components.md)。
## 11.7 跨端对象与同步
Endorphin 对象可以由平台识别、管理和存储,其存续不必绑定到某次客户端运行或某台机器的内存。客户端需要使用远程对象的数据时,可以建立本地对象,并关联到平台管理的同一对象;后续变化通过网络同步到本地。
这里的“平台对象”描述已有 Object 模型的管理方式,不另设 PlatformObject 基础类型,也不表示所有临时值都必须永久登记。对象类型、atom 与资源 ID 的主要定义见[Object、atom 与资源 ID](07-top-level-types/README.md#objectatom-与资源-id)。
### 对象身份与本地副本
平台保存的是对象的身份、类型关联及需要保留的内容或状态。执行代码使用它时,仍需要在执行端准备相应的内存表示;平台存储并不消除运行时内存。
客户端为远程对象准备的本地对象称为本地副本。它保存已取得的类型化数据及目标对象的身份关联,供本地代码读取或使用。客户端和服务器上的物理表示分别占用各自的内存;通过资源 ID 关联到同一逻辑对象,不表示共享同一个内存地址。
| 层次 | 表达什么 | 不单独保证什么 |
| --- | --- | --- |
| 平台对象身份 | 正在关联哪一个对象 | 对象的当前状态已经到达客户端 |
| 平台保存的内容或状态 | 对象在平台中的保留信息 | 每个执行端都已加载完整内容 |
| 本地副本 | 当前执行端已经取得、可以使用的数据 | 数据始终最新,或本地修改已经保存 |
| 同步关联 | 后续变化继续传递到关联的副本 | 多端瞬时一致,或任意冲突自动解决 |
本地副本的关联身份不代替类型检查和访问授权。平台按已确定的对象类型恢复可使用的数据,不仅凭收到的字段结构认定其类型。
### 获取与后续同步
下面描述平台职责,不规定源码接口、传输编码或服务器部署方式:
```text
客户端请求关联一个获准访问的对象
→ 平台解析目标身份并取得可交付的内容或状态
→ 数据通过网络传到客户端
→ 客户端准备类型化的本地副本,保留目标身份关联
→ 建立持续关联后,后续变化继续通过网络传递
→ 客户端更新可使用的本地数据
```
一次读取只取得该次结果;建立持续关联后,才具有跟随后续变化的语义。因此,读取对象不自动表示永久订阅,关联同一对象也不表示各端此刻拥有同样的数据。
同步遵守对象自身的更新契约。内容对象和定义对象的修改产生新的资源 ID,已保存的确定引用继续指向原对象;同步不能把这种引用静默改成新定义。类型允许改变状态的运行对象则可以保留身份,并把合法的状态变化交付给本地副本。跟随命名入口选用新对象与同步同一运行对象的状态是两种不同关系。
取得代码或函数对象的本地副本只准备了定义。执行函数仍需要满足调用与输入规则;对象关联本身不决定函数何时执行或在哪个执行端运行。Preflight 检查定义及依赖,inflight 管理实际获取、调用与运行状态,阶段名称也不决定执行位置。
### 同一对象可以暂时具有不同的可见状态
沿用商品定价场景,假定 `atelier:shop.pricing` 中有一个允许改变价格引用的共享运行对象,资源 ID 用 `price-state-1` 示意。该名称不规定正式类型或 ID 格式;以下是行为示意,不是源码:
| 时刻 | 平台保存的价格状态 | 客户端 A 的本地副本 | 客户端 B 的本地副本 |
| --- | --- | --- | --- |
| 两端已取得初始状态 | 引用数值 100 | 引用数值 100 | 引用数值 100 |
| 平台已接受一次改价,更新尚未到达 | 引用数值 90 | 仍引用数值 100 | 仍引用数值 100 |
| 更新已到达 A | 引用数值 90 | 引用数值 90 | 仍引用数值 100 |
| 更新已到达两端 | 引用数值 90 | 引用数值 90 | 引用数值 90 |
各端始终关联 `price-state-1`。发生变化的是运行对象的价格引用,不是把常量 100 原地改成 90;两个数值仍分别是不可变内容。
若修改由客户端发起,本地提出修改、平台接受修改和其他副本收到更新也是不同的时刻。不能仅凭本地赋值或界面已显示新值,就认定平台已经接受并保存修改。是否允许提前展示本地修改、如何确认结果以及如何处理同时改价,统一保留在[跨端对象与同步的规范状态](../appendices/specification-status.md#跨端对象与同步)。
### 副本、关联与平台对象的生命周期
关闭客户端、释放本地副本或解除同步关联,不等于删除平台对象。对象是否继续保留遵守平台的生命周期和有效保留根规则;由平台存储也不表示永不回收。客户端再次访问时可以重新取得数据,恢复到哪个状态以及怎样接续遗漏的更新仍待定义。
对象尚未取得、连接中断、更新失败和目标已不可访问,需要与成功取得数据区别处理。具体状态类型、授权撤销后的行为、删除规则及关联解除接口尚未定义,不能把这些情况伪装成正常的空对象或零值。
[上一章:数据读取](10-data-access.md) · [下一章:UI 组件](12-ui-components.md) · [目录](../README.md)
+4 -2
View File
@@ -1,9 +1,11 @@
# 13. Agent
agent 是与 class、function 并列、可归属于 namespace 的语言资源声明。它为共有的变量、函数和其他合法结构建立 agent 内部作用域,并将这些成员与模型驱动的执行、工具使用、记忆、状态和控制流关联起来。
Agent 是具有模型驱动执行、工具使用、记忆、状态和控制能力的对象类型。Agent 类型对象是 Type 的实例,并继承 Object。agent 构造入口自身也是对象,用于建立具有名义身份的具体 Agent 类型对象,并为其成员建立内部作用域和运行关联。
agent 的语言地位和本章各项职责已经确定;声明骨架及成员关联的具体写法仍是设计稿,见[规范状态](../appendices/specification-status.md#agent)。这些能力由语言与平台共同提供,不以安装某个宿主语言的 Agent 包作为声明前提。
以 PricingAssistant 为例:PricingAssistant 是 Type 的实例,其运行对象 first 是 PricingAssistant 的实例。采用 PricingAssistant 继承 Agent 的关系时,first 获得相应运行能力,但 PricingAssistant 类型对象不会因此变成运行中的 agent。实例化与继承分别保存,候选构造和使用示例见[Agent 对象](07-top-level-types/agents.md)。
## 13.1 声明、成员与作用域
agent 声明拥有名称和 namespace 归属。内部使用 Endorphin 共有的变量、函数、class 和其他允许的声明或表达式;每种结构仍遵守自身的语法位置与类型规则。允许共有结构不表示可以在任意位置直接使用 return 等语句。
@@ -135,4 +137,4 @@ Preflight 检查可静态确定的成员、函数类型、引用关系和控制
实例化、任务交付、对外入口、实例标识和版本更新的具体形式仍待定义。本章不为它们补造 start、run 或 submit 等默认 API。
[上一章:UI 组件](12-ui-components.md) · [附录:形式文法](../appendices/formal-grammar.md) · [目录](../README.md)
[上一章:UI 组件](12-ui-components.md) · [下一章:交互式会话(REPL)](14-repl.md) · [附录:形式文法](../appendices/formal-grammar.md) · [目录](../README.md)
+109
View File
@@ -0,0 +1,109 @@
# 14. 交互式会话(REPL)
REPL 是持续接收输入、检查并求值、呈现结果的交互式会话。Endorphin 的 REPL 可作为平台对象和程序能力的交互入口:使用者可以准备定义、执行表达式、查看对象,并观察调用与同步的后续状态。
本章是设计提案。它复用已有对象、Preflight/inflight、权限和呈现模型;会话行为是候选设计,尚未确定启动命令、控制命令、完整输入文法或原生会话类型。完整未定范围见[规范状态](../appendices/specification-status.md#repl)。
## 14.1 会话上下文
建议一次 REPL 会话保留当前输入环境,使后续输入可以使用前面准备的定义、名称绑定和结果对象。会话上下文包含:
| 信息 | 用途 |
| --- | --- |
| 操作身份与可用权限 | 判断本次查看、调用、编辑或同步是否允许 |
| workspace 与 namespace 上下文 | 解释资源归属及当前查找范围 |
| 已准备的定义与依赖 | 为后续输入提供确定的函数、类型和资源引用 |
| 会话名称绑定 | 在多次输入之间引用已有值 |
| 调用记录与结果引用 | 查看本次输入的等待、成功、失败或后续状态 |
| 本地副本与同步关联 | 使用已取得的数据,并接收后续变化 |
workspace 和 namespace 上下文由 REPL 外部选择,不增加源码中的 namespace 自声明,也不决定代码一定在客户端或服务器执行。会话范围的临时名称与 namespace 中的平台命名入口分别处理。
建议在会话中准备声明时,先建立会话可用定义;将定义登记到共享 namespace 是单独的编辑动作,遵守 w 权限。这样可以试验逻辑,再选择保存范围。临时定义怎样获得资源身份、保留多久以及如何登记,仍需正式规则。
“REPL 会话”描述交互上下文,不预先确定它必须是原生 Session 类型。Session 的候选设计见[运行与状态](07-top-level-types/execution.md#session)。
## 14.2 提交输入与执行时机
建议用户提交一个完整输入单元后,REPL 先进行 Preflight 检查。表达式及需要取得实际值的绑定通过检查后进入 inflight;定义则准备为后续可用的对象,不因提交声明而执行其中的业务逻辑。
| 提交内容 | 检查与准备 | 可观察效果 |
| --- | --- | --- |
| use 声明 | 解析 namespace 与可用声明 | 后续输入可按名称规则引用依赖,不执行整个 namespace |
| 函数、类型或 agent 定义 | 检查定义及依赖 | 提供会话可用的定义,不调用函数、读取业务数据或启动 agent |
| 数值或普通表达式 | 检查名称及类型 | 求值并呈现结果 |
| 包含调用的表达式 | 检查目标和参数 | 使用实际参数发起调用,呈现结果或等待状态 |
| 名称绑定 | 检查右侧表达式及绑定规则 | 求得值后建立会话绑定,供后续输入使用 |
| 已有对象的名称 | 解析当前绑定 | 查看对象;函数对象的查看不等于调用 |
一次提交可以是多行函数定义;逐个字符输入和编辑尚未提交的文本不触发业务执行。输入单元边界、顶层绑定文法及多个语句的处理仍待定义,本表不把函数体内的全部语句直接扩展到顶层。
定义、实际调用与结果对象的生命周期沿用[Preflight 与 inflight](05-preflight-and-inflight.md)。REPL 的反复接收输入属于宿主交互调度;它不要求无任务时持续执行某个业务函数,也不要求为交互环境引入字节码。
## 14.3 定价示例
下面是拟议交互过程,不是实际执行日志,也不是完整程序。会话外部上下文为 `market:shop.checkout`,依赖第 9 章的 [discountedPrice](09-functions-and-calls.md#91-函数声明)。假定操作用户获准使用目标函数,其名称在导入后可见且没有冲突;amount 的跨输入保留属于本章提出的会话绑定行为。
```text
输入:use atelier:shop.pricing
结果:依赖已准备,尚未调用定价函数
输入:discountedPrice
结果:查看函数对象及获准取得的接口信息
输入:discountedPrice(100, 10)
结果:90
输入:let amount = discountedPrice(100, 10)
结果:amount 绑定到本次成功取得的数值 90
输入:discountedPrice(amount, 5)
结果:85
```
输入函数名时,REPL 处理函数对象;提交调用表达式时,才使用实际参数执行。后一调用使用已有 amount,因此按定价例子先得到 90,再得到 85。若初始参数换为 80 与 7,amount 为 73,再扣减 5 的结果为 68。
新输入绑定的普通结果不自动变成持续计算。amount 在本例持有一次调用的结果;要持续跟随远程对象变化,需要另行建立[同步关联](11-resource-access-and-presentation.md#117-跨端对象与同步)。
## 14.4 结果对象与呈现
建议 REPL 将一次输入的执行记录与成功结果对象分别保留。执行记录回答“这次输入是否完成”,结果对象回答“取得了什么,可以怎样使用”。输出到屏幕的文本只是对象的一种呈现,不代替对象身份与类型。
数值和文本可以直接显示;函数显示可查看的定义或接口;其他类型按已有呈现契约处理。取得可渲染值时可以提供界面预览,媒体或复杂对象可以提供相应查看方式。具体类型与默认查看器仍遵守[资源访问与呈现](11-resource-access-and-presentation.md#116-按类型呈现的边界)的待定范围。
建议允许使用者将结果关联到明确名称,继续传入函数或检查类型及身份;不预先引入隐式的“上一个结果”变量。显示资源 ID、类型身份、加载状态或同步状态属于查看能力,其源码接口与界面布局尚未确定。
查看结果不自动重新执行产生它的表达式。尤其对带业务写入的调用,展开对象、刷新界面或重开历史记录不能成为隐式重试的理由。
## 14.5 等待、失败与持续更新
远程调用未完成时,建议 REPL 显示该次输入的等待状态;已有结果仍可查看。后续输入如果依赖未就绪结果,不能把等待状态当成成功值。第一版可先采用按提交顺序处理求值输入的方式;是否允许独立输入在等待期间并发执行,仍需确定。
| 情况 | 应保留的区别 |
| --- | --- |
| Preflight 发现输入错误 | 报告诊断,不进入该输入的业务执行 |
| 调用尚未完成 | 标识本次调用,不伪造成功结果 |
| 执行或网络发生失败 | 区分已知失败与结果尚不能确认;业务效果不因此保证已回滚 |
| 一次读取成功 | 返回该次结果,不自动持续订阅 |
| 对象保持同步关联 | 可以继续更新本地副本,原获取调用的完成状态与副本同步状态分别处理 |
| 请求取消调用 | 表示请求停止,不能保证已完成的远程业务效果被撤销 |
建议同步更新关联到原对象或结果记录,不占用新的输入位置,也不重新求值所有历史表达式。一次获取完成后,副本仍可接收更新;连接中断后,本地已有数据与“同步是否有效”应分别可见。版本与新鲜度规则见[跨端对象与同步的规范状态](../appendices/specification-status.md#跨端对象与同步)。
## 14.6 历史、定义更新与会话结束
建议把输入历史与可恢复的会话状态分开:历史记录便于查阅,不保证对象仍可取得,也不充当恢复全部状态的脚本。重新打开历史不自动重放调用;保存或恢复会话不应以重复执行业务写入来恢复结果。
修改函数定义遵守新的资源身份规则。会话中的名称如何选用新定义属于输入环境的绑定规则;已有调用和已经保存的确定引用仍保留原目标。REPL 不以“函数名相同”为由替换正在执行的定义。
结束会话需要分别处理输入环境、本地副本、同步关联、未完成调用和平台资源。建议提供查看未完成活动及解除关联的操作;结束会话是否取消某个任务、平台是否继续保留结果、离线后如何恢复,不由关闭输入窗口单独决定。
平台对象是否回收仍依据有效保留根及生命周期;会话历史是否作为保留根、解除关联如何影响保留关系尚未确定。结束会话不等于删除该会话曾经访问的全部平台对象。
## 14.7 首版设计范围
建议首版先覆盖输入单元、会话绑定、Preflight 诊断、普通表达式与函数调用、类型化结果查看,以及等待和失败记录。在此基础上,再加入平台对象获取、同步状态查看与解除关联。
命令名、快捷键、并发求值、会话持久化、定义登记接口和断线恢复不是已有源码规则。REPL 也不自动成为调试器、数据库管理器或任意远程执行入口;其操作继续受类型、调用契约和权限约束。各项候选与待定边界集中维护在[REPL 规范状态](../appendices/specification-status.md#repl)。
[上一章:Agent](13-agents.md) · [附录:规范状态](../appendices/specification-status.md) · [目录](../README.md)