@calcit/procs 0.12.19 → 0.12.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/editing-history/202507161633-wasm-data-structures.md +61 -0
  3. package/editing-history/20260416-1936-predicate-narrowing-expansion.md +31 -0
  4. package/editing-history/202604161507-wasm-data-structures-and-rfc-rename.md +27 -0
  5. package/editing-history/202604161520-wasm-bitwise-and-match.md +21 -0
  6. package/editing-history/202604161542-wasm-cross-ns-host-imports.md +38 -0
  7. package/editing-history/20260417-0026-wasm-rest-args.md +62 -0
  8. package/editing-history/202604170048-wasm-type-of.md +70 -0
  9. package/editing-history/202604170051-wasm-derived-predicates.md +34 -0
  10. package/editing-history/202604170132-monomorphize-map-filter.md +50 -0
  11. package/editing-history/202604170135-monomorphize-includes-reverse.md +31 -0
  12. package/editing-history/202604170140-fold-type-predicates.md +44 -0
  13. package/editing-history/202604170154-generic-dispatch-records-tuples.md +52 -0
  14. package/lib/calcit.procs.mjs +39 -6
  15. package/lib/package.json +1 -1
  16. package/package.json +1 -1
  17. package/rfc/02-04-runtime-traits-plan.md +613 -0
  18. package/rfc/02-14-project-modernization-roadmap.md +229 -0
  19. package/rfc/02-17-register-platform-api-rfc.md +115 -0
  20. package/rfc/02-18-language-theory-evolution-plan.md +367 -0
  21. package/rfc/02-23-optional-record-macro-plan.md +30 -0
  22. package/rfc/03-05-function-schema-dual-track-rfc.md +162 -0
  23. package/rfc/03-16-runtime-boundary-refactor-plan.md +546 -0
  24. package/rfc/03-18-query-def-tree-show-chunked-display-plan.md +301 -0
  25. package/rfc/04-13-call-arg-literal-rewrite-rfc.md +205 -0
  26. package/rfc/04-13-type-slot-mechanism-rfc.md +194 -0
  27. package/rfc/04-15-match-syntax-rfc.md +175 -0
  28. package/rfc/04-15-type-directed-optimization-catalog.md +170 -0
  29. package/rfc/04-15-wasm-compilation-feasibility.md +236 -0
  30. package/rfc/04-16-wasm-data-structures.md +192 -0
  31. package/rfc/README.md +40 -0
  32. package/ts-src/calcit.procs.mts +33 -6
@@ -0,0 +1,613 @@
1
+ # Runtime Traits for Calcit (Draft)
2
+
3
+ > 目标:在运行时提供一套 Trait 机制,即使无法静态检查,也能把错误前移到调用点,并允许类型级别的能力声明(如 `Show`、`Add`、`Multiply` 等)。
4
+
5
+ > 文档说明(更新于 2026-02-08):本文件用于“解释当前实现 + 修正计划”。其中“当前实现/分派规则”以现有 Rust runtime / preprocess / JS backend 的真实行为为准;计划部分提供分阶段目标与验收口径。
6
+
7
+ ## 内置 Trait 设计
8
+
9
+ 参考 Haskell (Eq, Ord, Show, Num, Foldable, Functor) 与 Rust (Display, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Iterator, Add, Mul, From/Into) 的设计,结合 Calcit 的动态类型特性,定义以下内置 Trait:
10
+
11
+ ### 核心 Trait 分类
12
+
13
+ #### 1. 显示与调试 (Display & Debug)
14
+
15
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
16
+ | --------- | ------------------------ | -------------------- | ------------ | --------- |
17
+ | `Show` | `(show x) -> :string` | 人类可读的字符串表示 | `Show` | `Display` |
18
+ | `Inspect` | `(inspect x) -> :string` | 调试用的详细表示 | `Show` | `Debug` |
19
+
20
+ **默认实现**: 所有内置类型 (`nil`, `bool`, `number`, `string`, `tag`, `symbol`, `list`, `map`, `set`, `tuple`, `record`, `fn`) 都有默认实现。
21
+
22
+ #### 2. 相等与比较 (Equality & Ordering)
23
+
24
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
25
+ | --------- | ----------------------- | ---------------------- | ------------ | ----------- |
26
+ | `Eq` | `(eq? x y) -> :bool` | 相等性判断 | `Eq` | `PartialEq` |
27
+ | `Compare` | `(compare x y) -> :tag` | 返回 `:lt`/`:eq`/`:gt` | `Ord` | `Ord` |
28
+
29
+ **默认实现**:
30
+
31
+ - `Eq`: 所有值类型
32
+ - `Compare`: `number`, `string`, `tag`, `list`(字典序)
33
+
34
+ #### 3. 算术运算 (Arithmetic)
35
+
36
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
37
+ | ---------- | ---------------------- | --------- | ------------ | --------- |
38
+ | `Add` | `(add x y) -> 'T` | 加法/拼接 | `Num (+)` | `Add` |
39
+ | `Subtract` | `(subtract x y) -> 'T` | 减法 | `Num (-)` | `Sub` |
40
+ | `Multiply` | `(multiply x y) -> 'T` | 乘法 | `Num (*)` | `Mul` |
41
+ | `Divide` | `(divide x y) -> 'T` | 除法 | `Fractional` | `Div` |
42
+ | `Negate` | `(negate x) -> 'T` | 取负 | `Num negate` | `Neg` |
43
+
44
+ **默认实现**:
45
+
46
+ - `number`: 全部算术 Trait
47
+ - `string`: `Add`(字符串拼接)
48
+ - `list`: `Add`(列表连接)
49
+
50
+ #### 4. 集合操作 (Collection)
51
+
52
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
53
+ | ---------- | ----------------------------- | ------------- | ------------ | ------------ |
54
+ | `Len` | `(len x) -> :number` | 长度/大小 | `length` | `len()` |
55
+ | `Empty` | `(empty? x) -> :bool` | 是否为空 | `null` | `is_empty()` |
56
+ | `Contains` | `(contains? x item) -> :bool` | 包含检查 | `elem` | `contains()` |
57
+ | `Get` | `(get x key) -> 'V` | 按键/索引取值 | `lookup` | `get()` |
58
+
59
+ **默认实现**: `string`, `list`, `map`, `set`
60
+
61
+ #### 5. 可迭代 (Iterable)
62
+
63
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 | 备注 |
64
+ | ---------- | ----------------------- | ---------- | ------------ | ---------------- | ------------------------------------ |
65
+ | `Foldable` | `(fold x init f) -> 'A` | 折叠/归约 | `Foldable` | `Iterator::fold` | ✅ 命名来自 Haskell |
66
+ | `Functor` | `(fmap x f) -> 'T` | 保结构映射 | `Functor` | `Iterator::map` | 🎯 **改名建议**:用 Haskell 正统命名 |
67
+ | `Iterable` | `(iter x) -> iterator` | 获取迭代器 | - | `IntoIterator` | 统一迭代抽象 |
68
+
69
+ **动态语言务实方案(可选):**
70
+
71
+ - 不单独定义 `Functor`/`Filterable`,直接在集合类型上提供 `.map`/`.filter` 方法
72
+ - 或统一为 `Collection` trait,包含 `map`, `filter`, `fold` 全套操作
73
+ - 类似 Rust 的 `Iterator` 或 JavaScript 的 `Array` 方法
74
+
75
+ **默认实现**: `list`, `map`, `set`, `string`
76
+
77
+ **设计权衡说明:**
78
+
79
+ - Haskell 的 `Functor`/`Monad` 威力在于类型系统保证代数定律
80
+ - 动态语言无法静态检查这些定律,过度抽象可能适得其反
81
+ - 推荐:借鉴概念,但保持实用导向(用户更关心"能不能 map",而非"是不是 Functor")
82
+
83
+ #### 6. 哈希与克隆 (Hash & Clone)
84
+
85
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
86
+ | ------- | --------------------- | ------ | ------------ | --------- |
87
+ | `Hash` | `(hash x) -> :number` | 哈希值 | `Hashable` | `Hash` |
88
+ | `Clone` | `(clone x) -> 'T` | 深拷贝 | - | `Clone` |
89
+
90
+ **默认实现**: 所有不可变值类型自动满足(Calcit 默认 immutable)
91
+
92
+ #### 7. 默认值与转换 (Default & Conversion)
93
+
94
+ | Trait | 方法签名 | 描述 | Haskell 对应 | Rust 对应 |
95
+ | --------- | ----------------------- | ---------- | ------------ | ----------- |
96
+ | `Default` | `(default T) -> 'T` | 类型默认值 | `Default` | `Default` |
97
+ | `From` | `(from T source) -> 'T` | 类型转换 | - | `From/Into` |
98
+
99
+ **默认实现**:
100
+
101
+ - `Default`: `nil`→`nil`, `number`→`0`, `string`→`""`, `list`→`[]`, `map`→`{}`, `set`→`#{}`
102
+ - `From`: 常见转换如 `number->string`, `list->set`, `map->list`
103
+
104
+ ### Trait 定义语法(当前实现)
105
+
106
+ 当前 `deftrait` 宏仅用于声明 trait 名称与方法列表,内部调用 `&trait::new`。
107
+
108
+ ```cirru
109
+ deftrait Show :show
110
+ deftrait Eq :eq?
111
+ deftrait Compare :compare
112
+ ```
113
+
114
+ > 说明:默认实现、依赖与方法签名描述仍在规划中,尚未落地。
115
+
116
+ ### Trait 实现语法(当前实现)
117
+
118
+ 使用 `impl-traits` 函数式组合的方式为类型添加 Trait 实现(当前仍以 record 承载 impl,计划升级为独立 impl 结构,见后文):
119
+
120
+ ```cirru
121
+ ; 完整示例:为 Point 类型实现 Show 和 Eq trait
122
+ let
123
+ ; 1. 定义基础 struct
124
+ Point0 $ defstruct Point (:x :number) (:y :number)
125
+
126
+ ShowTrait $ deftrait Show
127
+ EqTrait $ deftrait Eq
128
+
129
+ ; 2. 定义 Show trait 的实现 (record 形式)
130
+ show-impl $ %{} ShowTrait
131
+ :show $ fn (p)
132
+ str "|Point(" (.x p) ", " (.y p) ")"
133
+
134
+ ; 3. 定义 Eq trait 的实现
135
+ eq-impl $ %{} EqTrait
136
+ :eq? $ fn (a b)
137
+ and (= (:x a) (:x b)) (= (:y a) (:y b))
138
+
139
+ ; 4. 使用 impl-traits 组合,得到带 trait 实现的 struct
140
+ Point $ impl-traits Point0 show-impl eq-impl
141
+
142
+ ; 5. 用 struct 创建 record 实例
143
+ p1 $ %{} Point (:x 3) (:y 4)
144
+ p2 $ %{} Point (:x 3) (:y 4)
145
+
146
+ ; 6. 调用 trait 方法
147
+ println (.show p1) ; => "Point(3, 4)"
148
+ println (.eq? p1 p2) ; => true
149
+
150
+ ; impl-traits 可以接受多个 trait impl
151
+ ; (impl-traits struct-def impl1 impl2 impl3 ...)
152
+ ```
153
+
154
+ **约束(更新)**:`impl-traits` 只接受 **struct/enum** 作为输入。record/tuple 是实例值,必须从已经挂载 impl 的 struct/enum 创建(如 `%{} Struct ...` 或 `%:: Enum ...`)。
155
+
156
+ ### Trait 约束与标注(新增)
157
+
158
+ `assert-traits` 用于在编译期提供“trait 标注”,并在运行时进行检查:
159
+
160
+ - **编译期标记**:将本地变量标注为 trait 类型,供方法解析与类型提示使用。
161
+ - **运行时检查**:确保值确实实现该 trait(缺失方法时直接报错)。
162
+
163
+ 补充(与当前实现一致):
164
+
165
+ - `assert-traits` 是一个语法(syntax),会在 preprocess 阶段被展开为对内建过程 `&assert-traits` 的调用;runtime 并不直接执行 `assert-traits` 语法本身。
166
+ - 当前实现要求第一个参数必须是 **local**,用于把 type-info 写回作用域类型表并用于后续方法校验/类型提示。
167
+
168
+ **行为细则(基于当前实现,补充更具体的定义):**
169
+
170
+ 1. **两种写法与作用范围**
171
+
172
+ - **函数 body 顶层写法**(推荐,作为函数前置约束):
173
+ - 写在函数 body 顶层的 `assert-traits x Trait` 被视为“参数/局部的全局约束”。
174
+ - 静态分析会把它当作参数类型提示来源(与 `assert-type` 同级别),影响整个函数体内的 `.method` 校验与提示。
175
+ - 运行时会在执行到该表达式时进行检查(缺失方法则抛错)。
176
+
177
+ - **函数 body 内部嵌套写法**(表达式/返回值约束):
178
+ - `assert-traits` 作为表达式参与计算时,主要用于约束该表达式(及其返回值链路);适用于在局部链路上增加约束,减少 `let _ ...` 这类“仅为检查而写”的绑定。
179
+ - 当前实现的参数类型提示扫描会遍历函数体中的 `assert-traits`,因此严格来说嵌套写法也可能被识别为参数提示;但约定上仅将顶层写法视为“函数级前置约束”。
180
+
181
+ 2. **静态分析(preprocess)行为**
182
+
183
+ - 会在当前作用域把 local 的 type-info 写入 `scope_types`,供后续 `.method` 校验/补全使用。
184
+ - `assert-traits` 参数中的 trait 解析规则:
185
+ - 能解析为 trait 定义的,进入 trait 集合。
186
+ - 若解析不到 trait,会降级为自定义类型标注,仅用于类型提示(不参与方法校验)。
187
+ - 多个 trait 通过 **append** 形成 `TraitSet`;当多次 `assert-traits` 作用于同一个 local 时,后者的 type-info 会覆盖前者。
188
+ - 若 local 已有**具体类型**标注(如 record/struct/enum 或内置类型),`assert-traits` 不会覆盖该具体类型,以保证后续方法内联与 impl 查找仍可进行。
189
+
190
+ **静态分析可执行边界(重要)**
191
+
192
+ - 只有顶层 `ns/def` 可在构建快照阶段执行;`defn`/`defmacro`/thunk 内部表达式不会被执行,只做浅层预处理。
193
+ - 因此 `defstruct`/`defenum`/`impl-traits` 若写在函数体内,静态分析阶段无法拿到 impl 列表,也就无法做方法内联与精确分派。
194
+ - 建议把结构定义与 impl 绑定放在**顶层定义**(单独 `def`),使 preprocess 可稳定使用这些值进行分析与优化。
195
+
196
+ 3. **运行时行为**
197
+
198
+ - 预处理会把 `assert-traits` 展开成一连串 `&assert-traits` 调用,运行时逐个检查 trait 是否实现。
199
+ - 检查顺序按写入顺序执行;当 trait 列表存在重复方法时,实际方法分派仍遵循 impl 分派规则(user impls last-wins / core impls first-wins)。
200
+ - **内置类型限制**:list/map/set/string/number 等内置数据结构的 impl 列表是固定的,`assert-traits` **不会** 在运行时扩充它们的可用方法,只做“默认实现是否存在”的校验。
201
+ - **静态/运行时不一致**:由于静态分析信息有限,preprocess 的 trait 标注可能比运行时更宽松;当前允许这种不一致存在。
202
+
203
+ 4. **顺序与覆盖**
204
+
205
+ - trait 信息的记录是 **append 模式**,但对方法分派的“命中优先级”仍以 impl 链为准;当存在多重 trait/impl 时,**从末尾开始命中**(last-wins)是用户自定义 impl 的生效方向。
206
+ - `assert-traits` 只影响“能不能调用/能否单态化”的判断,不改变实际方法分派的实现来源。
207
+
208
+ ```cirru
209
+ ; 在调用点标注并断言 trait 能力
210
+ assert-traits x Show
211
+ ; 允许编译期把 x 视作 trait object,方便后续的 .show/.eq? 等方法校验
212
+ ```
213
+
214
+ **类型标注支持**:trait 定义可作为类型标注值使用(与 struct/enum 类似)。
215
+
216
+ - 例:`assert-traits x Show` 会把 `x` 的类型标注为 `trait Show`。
217
+
218
+ ### 分派规则(当前实现)
219
+
220
+ 当前 `.method` 调用(包含 trait 方法)本质上是对“impl records 列表”的查找。
221
+
222
+ 分派来源与优先级:
223
+
224
+ | 场景 | impl 来源 | 覆盖策略 | 扫描方向 | 备注 |
225
+ | ------------ | ---------------------------------------------------------------- | -------------- | -------- | ------------------------------------------------------------ |
226
+ | 用户自定义值 | Record/Tuple/Struct/Enum 实例的 `impls`(由 `impl-traits` 追加) | **last-wins** | 从尾到头 | 支持“后追加覆盖前实现”(append-to-override) |
227
+ | 内置类型 | `calcit.core` 中的 `&core-*-impls`(core impl list) | **first-wins** | 从头到尾 | 保持 core 列表顺序语义(如 list `.add` vs Add trait `:add`) |
228
+
229
+ 1. **用户自定义值的 `impls`(Record/Tuple/Struct/Enum 实例)**
230
+
231
+ - `impl-traits` 会把新的 impl record **追加** 到值的 `impls` 末尾(不可变地返回新值)。
232
+ - 查找策略:**last-wins**(从尾到头扫描,先命中先调用)。
233
+ - 目的:支持稳定的“后追加覆盖前已有实现”的工作流。
234
+
235
+ 2. **内置类型的 core impl 列表(list/map/number/string/set/fn 等)**
236
+
237
+ - runtime 会把值映射到 `calcit.core` 中的 `&core-*-impls`(这是一个 record 或 record 列表)。
238
+ - 查找策略:**first-wins**(从头到尾扫描,先命中先调用)。
239
+ - 目的:保持 `calcit.core` 中现有 impl 列表的顺序语义(已存在依赖顺序的案例:list 的 `.add` 与 Add trait 的 `:add` 同名时,core 列表顺序决定行为)。
240
+
241
+ 一致性要求:preprocess 的方法校验/内联与 JS backend 的 `invoke_method` 需要与上述规则保持一致(当前已对齐)。
242
+
243
+ ```cirru
244
+ ; 分派示例
245
+ .show 42 ; → 查找 number 的 Show 实现 → "42"
246
+ .show my-point ; → 查找 Point record 的 Show 实现 → "Point(1, 2)"
247
+
248
+ ; 显式 Trait 调用(计划,用于消歧义)
249
+ ; (trait-call Show :show 42)
250
+ ; (Show/show 42)
251
+ ```
252
+
253
+ ### 内置类型的 Trait 实现映射
254
+
255
+ - `nil`: Show, Inspect, Eq, Hash
256
+ - `bool`: Show, Inspect, Eq, Hash
257
+ - `number`: Show, Inspect, Eq, Compare, Add, Multiply, Hash
258
+ - `string`: Show, Inspect, Eq, Compare, Add, Len, Foldable, Functor, Hash
259
+ - `tag`: Show, Inspect, Eq, Compare, Hash
260
+ - `symbol`: Show, Inspect, Eq, Hash
261
+ - `list`: Show, Inspect, Eq, Compare, Add, Len, Foldable, Functor, Hash
262
+ - `map`: Show, Inspect, Eq, Len, Foldable, Functor, Hash
263
+ - `set`: Show, Inspect, Eq, Len, Foldable, Functor, Hash
264
+ - `tuple`: Show, Inspect, Eq, Len, Hash
265
+ - `record`: Show, Inspect, Eq, Len, Hash
266
+ - `fn`: Show, Inspect
267
+
268
+ ### 实施阶段(对照当前进度)
269
+
270
+ #### Phase 1: 基础 Trait 结构 ✅ **已完成**
271
+
272
+ 1. ✅ 定义 `CalcitTrait` 数据结构 (src/calcit/calcit_trait.rs)
273
+ 2. ✅ 在 `Calcit` enum 中添加 `Trait(CalcitTrait)` 变体
274
+ 3. ✅ 在 `calcit.core` 中定义 `Show`, `Eq`, `Add`, `Multiply`, `Len` 等核心 trait
275
+ 4. ✅ 内置类型自动拥有对应实现(已在运行时与 JS backend 对齐)
276
+ 5. ✅ `invoke_method` 支持 Trait 方法查找
277
+ 6. ✅ 从 `class` 系统迁移到 `trait` 和 `impls` (commit 73aa249)
278
+ 7. ✅ `impl-traits` 函数支持为 record/tuple/struct/enum 追加 impl
279
+ 8. ✅ JS backend 完整支持 CalcitTrait 及相关操作
280
+ 9. ✅ 移动内部实现到 `calcit.internal` 命名空间以清理代码结构
281
+
282
+ #### Phase 2: 语法支持 🔄 **部分完成**
283
+
284
+ 1. ✅ `deftrait` 宏定义(支持方法名 + 类型签名)
285
+ 2. ✅ 基础 trait 实现语法(通过 record + `impl-traits`)
286
+ 3. ✅ 测试覆盖:`test-traits.cirru` 包含 Show/Eq/Compare/Add/Len 等基础测试
287
+ 4. ✅ `defimpl` 最小宏定义(当前展开为 `defrecord!`,用于更清晰地定义 impl record)
288
+ 5. ⏳ `defimpl ... for ...`(让宏直接表达“trait + 目标类型/值”,并减少手写 `impl-traits` 的样板)
289
+ 6. ✅ `assert-traits` 运行时检查与编译期标注(当前限制:第一个参数需要是 local;preprocess 展开为 `&assert-traits`)
290
+ 7. ⏳ Trait 方法的显式调用语法(如 `Show/show` 或 `trait-call`)
291
+
292
+ #### Phase 3: 扩展 📋 **待实现**
293
+
294
+ 1. ⏳ 完整的集合 Trait (`Foldable`, `Mappable`, `Filterable`)
295
+ 2. ⏳ `Default`, `From` 转换 Trait
296
+ 3. ⏳ Trait 依赖(`requires`)与默认实现(`defaults`)
297
+ 4. ⏳ Trait 继承/组合
298
+ 5. ⏳ 更好的错误消息(trait 不匹配时的详细提示)
299
+ 6. ⏳ 性能优化(trait 查找缓存)
300
+
301
+ ---
302
+
303
+ ## 范围评估
304
+
305
+ ### 1) 核心数据结构与运行时
306
+
307
+ - **`Calcit` 新增变种**:`Trait`(已完成),新增 `Impl` 变种用于承载 trait impl(从 record 迁移)。
308
+ - **运行时上下文**:不单独引入 registry,内置 Trait 直接放在 `calcit.core`,其他 Trait 作为普通值附着在各自命名空间上。
309
+ - **调用分派**:方法调用/操作符调用在当前命名空间与 `calcit.core` 中解析 Trait 值,再执行绑定实现。
310
+ - **Trait 实现承载**:Traits 以组合方式使用,携带实现时统一使用 `Vec`;计划引入 `CalcitImpl` 作为一等结构,替代 record 承载(同时保留向后兼容的过渡层)。
311
+ - **错误模型**:为 trait 查找失败、约束不满足等错误引入新的错误类别与消息格式。
312
+
313
+ ### 2) 标准库/内建能力定义
314
+
315
+ - **内建类型能力**:
316
+ - `Show`:所有类型默认实现(或至少 `nil/bool/number/string/list/map/set/tuple`)。
317
+ - `Add`/`Multiply`:`number` 实现;`string` 可选实现 `Add`(拼接)但需明确语义。
318
+ - 其他可选:`Compare`、`Eq`、`Hash`、`Len`、`Index` 等。
319
+ - **内建函数/语法桥接**:
320
+ - `+`, `*`, `str` 等需要改为通过 trait 调用或保留内建分支 + trait 兜底。
321
+ - 现有 `method`/`record`/`tuple` 行为需要确定与 trait 的交互规则。
322
+
323
+ ### 3) 语言层定义与语法
324
+
325
+ - **Trait 定义**:动态类型前提下,可先按普通值定义 Trait,后续再考虑是否需要专用语法(如 `deftrait`)。
326
+ - **Trait 实现**:满足 Trait 的实现直接使用 record 表达,运行时通过 `with-class` 之类的机制挂上去(未来可能调整)。
327
+ - **Trait 约束表达**:考虑引入 `assert-traits`,用法类似 `assert-type`,用于声明约束与在调用处触发运行时检查。
328
+
329
+ ### 4) 运行时行为变更
330
+
331
+ - **左移报错**:
332
+ - 在调用处,若目标类型未实现 trait,直接抛错(避免进入执行体)。
333
+ - 在加载时注册 trait 实现并检测冲突(重复实现、签名不匹配等)。
334
+
335
+ ## 修改范围与复杂度
336
+
337
+ ### 高风险/广泛影响
338
+
339
+ - `Calcit` enum 变更(新增变种) → **所有 pattern match 需要更新**。
340
+ - `runner`/`preprocess`/`builtins` 的调用逻辑需要接入 trait 解析。
341
+ - `codegen` 需要考虑 trait 分派(JS backend 与 runtime 协议)。
342
+ - 现有内建操作(`+`, `*`, `.` method)需重新定义分派规则。
343
+
344
+ ### 中等影响
345
+
346
+ - `calcit.core` 标准库结构可能需要新增 trait 定义与实现。
347
+ - 错误与警告格式新增类型。
348
+
349
+ ### 低风险
350
+
351
+ - 文档、示例与 tests 的补充。
352
+
353
+ ## Breaking Changes 预估
354
+
355
+ - `Calcit` 匹配逻辑:新增 `Impl` 变种会导致编译错误与运行时路径调整(允许少量 breaking)。
356
+ - 内建操作行为:如果 `+/*` 改为 trait 分派,某些动态调用会改变错误时机。
357
+ - `method` 分派:同名方法在不同 impl 记录之间的覆盖策略会改变行为(当前已确定规则,见“分派规则”)。
358
+ - `str`/`format` 与 `Show` 的统一:输出可能略有不同。
359
+
360
+ ## 设计决策待确认
361
+
362
+ 1. Trait 分派优先级与覆盖策略:
363
+
364
+ - 已确定:用户自定义值 `impls` 采用 last-wins;内置类型 core impl 列表采用 first-wins。
365
+ - 待补:提供显式调用语法(`trait-call` / `Show/show`)用于消歧义,以及冲突时的告警/错误策略。
366
+
367
+ 2. Trait 的定义方式:
368
+ - 新语法 `deftrait` / `defimpl` vs 复用 record/defn
369
+ 3. Trait 是否支持泛型:
370
+ - 初期可不支持,后续扩展。
371
+ 4. 多实现冲突处理:
372
+ - 同一类型是否允许多个实现?冲突如何处理?
373
+
374
+ ## 建议实施阶段(草案)
375
+
376
+ ### Phase 1:基础结构
377
+
378
+ - 引入 `Trait` 数据结构,内置 Trait 放在 `calcit.core`(不新增 registry)。
379
+ - 内建 `Show` + `Number` 的 `Add/Multiply` 实现。
380
+ - 调整 `+`/`*` 使用 trait 分派(保留内建快速路径)。
381
+
382
+ ### Phase 2:语言层支持
383
+
384
+ - `deftrait` / `defimpl` 语法与 runtime 注册。
385
+ - 迁移 trait impl 承载:record -> `CalcitImpl`(保留兼容路径,逐步淘汰 record impl)。
386
+ - `assert-traits` / `requires` 运行时检查。
387
+
388
+ ### Phase 3:扩展与稳定
389
+
390
+ - 覆盖更多内建类型能力。
391
+ - 增加 tests(cirru 文件)覆盖 trait 注册、冲突、失败路径。
392
+
393
+ ---
394
+
395
+ ## 当前实现要点(补充)
396
+
397
+ - `deftrait` 已存在,展开为 `&trait::new`。
398
+ - `defimpl` 已存在(最小实现):展开为 `defrecord!`,用于更清晰地定义“trait impl record”(计划引入 `CalcitImpl` 后更新宏展开目标)。
399
+ - `impl-traits` 已在 Rust 与 JS backend 支持,可对 record/tuple/struct/enum 追加 impl。
400
+ - JS 侧已补齐 `CalcitTrait` 类型、`type-of`、`toString` 与 `&trait::new`、`&record:impl-traits` 等对应实现。
401
+ - `.method` 分派采用“混合优先级”:用户自定义值(record/tuple/struct/enum 实例)为 last-wins,内置类型 core impl 列表为 first-wins。
402
+ - `assert-traits` 已作为 preprocess 语法落地:写入 local 的 type-info,并展开为 `&assert-traits` 做运行时检查(当前限制:第一个参数需要是 local)。
403
+
404
+ ---
405
+
406
+ ## 近期执行计划(从简单稳定开始)
407
+
408
+ > 目标:先把行为与回归边界钉死,再推进语言层能力(`defimpl` / 显式 trait-call)。
409
+
410
+ 1. **清理与基线(半天内)**
411
+
412
+ - [ ] 把这轮 traits 改动按边界整理成 3 组:语义实现 / 测试 / 文档(便于 review)。
413
+ - [x] 检查是否有生成物被误纳入改动(如 `js-out/` 等):当前工作区改动仅包含计划/测试/core,未发现产物噪音需要纳入跟踪。
414
+
415
+ 2. **固化“分派优先级”规范 + 回归测试(1 天)**
416
+
417
+ - [x] 文档固化规则:builtin core impl list = first-wins;record/tuple impls = last-wins(append-to-override)。
418
+ - [x] 回归:core list 的 `.add` 不被 Add trait `:add` 覆盖(靠 core 列表顺序 + first-wins)。
419
+ - [x] 回归:record 上 `impl-traits` 追加实现能稳定覆盖旧实现(last-wins)。
420
+ - [x] 回归:tuple 上 `impl-traits` 覆盖链同样稳定(last-wins)。
421
+ - [x] 再补 1 个“更尖锐”的 Rust/JS 共用断言:不同 trait 提供同名方法时,仍以 `impl-traits` 追加顺序决定命中(覆盖 record + tuple)。
422
+
423
+ 3. **动态 trait 调用告警(1 天)**
424
+
425
+ - [x] 引入 `--warn-dyn-method`:在 `cr` 正常执行流程中,对无法单态化的 `.method` 调用给出 warning。
426
+ - [x] 规则:当 receiver 无法解析到具体 impl(类型为 `:dynamic`/未知),且未被 `assert-traits` 标注时触发告警。
427
+ - [x] 验收:warning 包含方法名与位置;`assert-traits` 后 warning 消失;Rust/JS 预处理行为一致。
428
+
429
+ 4. **补齐语言层能力:`defimpl` + 显式 trait-call(2~4 天)**
430
+
431
+ - [x] `defimpl`(v0):让“写 impl record”有标准入口,减少手写 `defrecord!` 的样板。
432
+ - [ ] `defimpl ... for ...`:让宏直接表达“trait + 目标类型/值”,并自动完成挂载(减少手写 `impl-traits`)。
433
+ - [ ] 显式 trait-call(如 `Show/show` 或 `trait-call`):提供绕开 `.method` 分派的稳定通道,便于 debug override 链。
434
+ - [ ] 验收:同一段代码在 preprocess 校验、Rust runtime、JS runtime 行为一致。
435
+
436
+ 5. **`assert-traits` 易用性补强(可选,1~2 天)**
437
+
438
+ - [ ] 支持 `assert-traits` 的第一个参数是任意表达式:preprocess 自动提升为临时 local 再做检查(纯语法糖)。
439
+ - [ ] 验收:`assert-traits (+ 1 2) ...` 可用,且错误位置/提示依然清晰。
440
+
441
+ 6. **冲突策略与可观测性(可选,2~3 天)**
442
+
443
+ - [ ] 提供“冲突诊断”开关:当同名方法多次出现时,打印候选列表/命中来源(对 last-wins 特别有帮助)。
444
+ - [x] 可选 debug proc:`&methods-of` / `&inspect-methods`,返回/打印某值当前 impl 链与可用方法集合,帮助定位“为什么命中这个实现”。
445
+
446
+ ---
447
+
448
+ ## Checklist(后续跟踪)
449
+
450
+ ### 🎯 推荐优先实现(短期,1-2周)
451
+
452
+ **理由:完善当前已有的 trait 机制,提升用户体验**
453
+
454
+ - [ ] **`defimpl` 宏**:简化 trait 实现语法
455
+ - 当前(已实现 v0):`defimpl MyTrait MyImpl (:method value) ...`(展开为 `defrecord!`,产出“impl record”)
456
+ - 仍待补齐:`defimpl MyTrait for MyType ...`(自动挂载/注册,减少显式 `impl-traits`)
457
+ - 优势:语义更清晰,自动完成 impl-traits 步骤
458
+ - 验收:宏展开在 Rust/JS 下语义一致;错误信息包含 trait/类型/缺失方法;`test-traits.cirru` 覆盖正常/冲突路径
459
+ - [ ] **显式 trait 调用语法**:解决方法名冲突
460
+ - 语法选项:`(trait-call Show :show x)` 或 `(Show/show x)`
461
+ - 用例:当一个类型实现多个 trait,且方法名冲突时
462
+ - 验收:可在运行时绕开 `.method` 的歧义(不受 impl 覆盖影响);preprocess 能做方法存在性与参数数量/类型校验;Rust/JS 行为一致
463
+ - [x] **`assert-traits` 运行时检查**:前移错误发现时机(已实现;当前限制:第一个参数需要是 local)
464
+ - 语法:`(assert-traits x Show)` 或 `(requires x Show)`
465
+ - 在函数入口检查参数是否满足 trait 约束
466
+ - 提供清晰的错误消息
467
+ - 下一步:扩展到函数参数/模式绑定等更多场景(不止 local)
468
+
469
+ ### 🔧 中期实现(3-4周)
470
+
471
+ **理由:扩展 trait 系统能力,支持更复杂的场景**
472
+
473
+ - [ ] **Trait 依赖(`requires`)**:声明 trait 之间的依赖关系
474
+ - 例:`Ord` 依赖 `Eq`
475
+ - 实现时自动检查依赖是否满足
476
+ - [ ] **默认实现(`defaults`)**:减少重复代码
477
+ - 在 trait 定义中提供默认方法实现
478
+ - 类型可以选择性覆盖
479
+ - [ ] **完整的集合 Trait(重新评估设计)**:
480
+ - **方案 A(Haskell 风格)**:独立 `Functor`/`Foldable` trait
481
+ - 优点:概念纯粹,严格分离关注点
482
+ - 缺点:在动态语言中过度抽象,用户学习成本高
483
+ - **方案 B(Rust/JS 风格)**:统一 `Collection` trait
484
+ - 包含 `map`, `filter`, `fold`, `count`, `empty?` 等全套操作
485
+ - 优点:实用导向,一站式接口
486
+ - 缺点:trait 体积大,部分类型可能只能实现子集
487
+ - **方案 C(混合)**:保留 `Foldable` 基础,`map`/`filter` 作为可选扩展
488
+ - 最小公约数是 `fold`(可实现 map/filter)
489
+ - 类型按需实现 map/filter 优化版本
490
+ - 🎯 **推荐**:先实现方案 B(务实路线),观察实际使用后再考虑拆分
491
+
492
+ - [ ] **冲突检测与覆盖策略**:
493
+ - 同一类型多 impl 时的优先级规则
494
+ - 重复注册时的警告机制
495
+
496
+ **Functor/Monad 补充说明:**
497
+
498
+ - 在 Calcit 这样的动态语言中,Monad 的核心价值(`>>=` 的类型组合)基本丧失
499
+ - 但 `Functor` (fmap) 仍有意义:统一"保结构变换"的概念
500
+ - 实际实现时可考虑:
501
+ - ✅ 提供 `fmap` 作为标准方法名(对 FP 用户友好)
502
+ - ✅ 同时保留 `.map` 别名(对主流用户友好)
503
+ - ❌ 不强制实现完整 Monad(`return`/`>>=` 在无类型约束时意义不大)
504
+
505
+ ### 🚀 长期规划(1-2月)
506
+
507
+ **理由:提升系统稳定性和性能**
508
+
509
+ - [ ] **转换 Trait (`Default`, `From`)**:
510
+ - 类型间的标准转换接口
511
+ - 减少手写转换函数
512
+ - [ ] **Trait 继承/组合**:
513
+ - 支持 trait 继承(如 `trait Ord extends Eq`)
514
+ - 或 trait 组合(如 `trait Num = Add + Multiply + ...`)
515
+ - [ ] **性能优化**:
516
+ - Trait 查找缓存(避免重复遍历)
517
+ - 内联常见 trait 方法(如 `show`, `eq?`)
518
+ - [ ] **更好的错误消息**:
519
+ - Trait 不匹配时显示期望 vs 实际
520
+ - 建议可能的解决方案
521
+ - [ ] **文档与示例**:
522
+ - 完整的 trait 使用指南
523
+ - 常见模式与最佳实践
524
+ - 更多 `test-traits.cirru` 测试用例
525
+
526
+ ### 📝 技术债务清理
527
+
528
+ - [x] ~~从 `class` 迁移到 `trait`~~ (已完成,commit 73aa249)
529
+ - [x] ~~移动内部函数到 `calcit.internal`~~ (已完成,commit fc78725)
530
+ - [ ] 解决 JS 编译模式的循环依赖问题
531
+ - 当前问题:`calcit.internal.mjs` 引用 `calcit.core.mjs` 导致初始化失败
532
+ - 可能方案:调整模块加载顺序或使用延迟初始化
533
+
534
+ ---
535
+
536
+ ## 实施建议
537
+
538
+ **下一步行动(按优先级):**
539
+
540
+ 1. **先做(低风险)**:清理基线 + 补齐“分派优先级”尖锐回归
541
+
542
+ - 把行为边界钉死,避免后续 `defimpl` / trait-call 引入难定位回归
543
+
544
+ 2. **然后(核心能力)**:`defimpl` 宏
545
+
546
+ - 降低写 impl 的样板,提高可读性
547
+
548
+ 3. **再做(可观测性/可维护)**:显式 trait 调用语法
549
+
550
+ - 解决方法名冲突与 override 链难 debug 的实际问题
551
+ - 为后续 trait 组合打基础
552
+
553
+ 3. **然后**:Trait 依赖 + 默认实现
554
+ - 这是更复杂的功能,依赖前面的基础
555
+ - 可以大幅减少样板代码
556
+
557
+ 4. **最后**:集合 Trait + 性能优化
558
+ - 在系统稳定后进行性能调优
559
+ - 逐步扩展 trait 覆盖范围
560
+
561
+ ---
562
+
563
+ ## 原有 Checklist(归档)
564
+
565
+ 以下是原计划中的项目,已整合到上面的分类中(按真实实现状态更新):
566
+
567
+ - [ ] `defimpl ... for ...`(包含方法名校验/去重规则)→ 短期优先(注:defimpl v0 已存在,仅产出 impl record)
568
+ - [x] `assert-traits` 运行时检查与错误消息格式(已实现;当前限制:第一个参数需要是 local)
569
+ - [ ] 显式 trait 调用语法(`trait-call` / `Show/show` 语法)→ 短期优先
570
+ - [ ] trait 依赖(`requires`)与默认实现(`defaults`)的表达与存储 → 中期实现
571
+ - [ ] 统一 `Compare` 的三态返回与 `&compare` 的关系(`<`/`>` 仅数字)→ 中期实现
572
+ - [ ] 冲突检测:同一对象多 impl 的覆盖顺序与警告策略 → 中期实现
573
+ - [x] ~~JS backend 与 Rust 行为一致性验证(新增 tests)~~ → 已有 test-traits.cirru
574
+ - [ ] 文档示例与 `test-traits.cirru` 覆盖更多失败路径 → 长期规划
575
+
576
+ ## 测试补充建议(cirru)
577
+
578
+ - `test-traits.cirru`:
579
+ - `Show` for number/string/list/map
580
+ - `Add`/`Multiply` for number
581
+ - 未实现时的错误提示
582
+ - 多实现冲突/重复注册
583
+
584
+ ## 附录:符号解析与 runtime-resolved symbols
585
+
586
+ 补充说明:在 trait/runtime 相关排障里,经常会遇到“文档里能看到/看不到某个符号”的认知差异。这里统一记录符号解析口径。
587
+
588
+ 目前符号大致分为:
589
+
590
+ - raw syntax symbols(例如 `&` `?` `~` `~@`)
591
+ - data symbol(通常由 `turn-symbol` 创建)
592
+ - local variables
593
+ - local definitions
594
+ - imported variables
595
+ - namespaced imported symbols
596
+ - imported default variables
597
+ - imported host variables
598
+
599
+ 当前它们在实现层很多都共享 `Calcit::Symbol{..}` 路径(这是已知历史包袱,后续仍需重构)。
600
+
601
+ 另外有一类 **runtime-resolved symbols**:由 parser/runtime 直接识别,不一定在 `calcit.core` 里作为普通 `CodeEntry` 出现。
602
+
603
+ - syntax symbols 来自 `CalcitSyntax`(例如 `assert-traits`)
604
+ - proc symbols 来自 `CalcitProc`(例如 `&trait-call`、`&inspect-type`、`register-calcit-builtin-impls`)
605
+
606
+ 因此检查符号可用性时,建议同时看:
607
+
608
+ - `src/cirru/calcit-core.cirru`(macro/def 暴露面)
609
+ - `src/calcit/syntax_name.rs` 与 `src/calcit/proc_name.rs`(runtime-native 符号)
610
+
611
+ ---
612
+
613
+ > 备注:该方案涉及 runtime/stdlib/codegen 全链路改造,建议先从最小可运行集开始迭代。