备份语言规范、顶级类型与运行时设计草稿

This commit is contained in:
2026-11-05 00:53:52 +08:00
parent 52f497671e
commit 5e185c53e3
31 changed files with 3594 additions and 64 deletions
+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)