Files
playbook/skills/tsl-syntax-reference/references/22_fmarray.md
T
csh 40a9885eb4 feat(tsl-syntax-reference): harden retrieval and restructure pages
- flag weak candidates (no intent/heading/identifier/tag hit) and exit 2
  when every candidate is weak: mis-hits used to be indistinguishable
  from real hits, so the retry-with-better-terms loop never fired
- accept multiple ids per --section for batch fetch, failing atomically
  on any unknown id so a partial fetch cannot pass as complete
- move query synonyms and page intent aliases to data/lexicon.json and
  enforce alias/page correspondence in --check; curation data no longer
  lives in the engine
- document the weak-hit rule, batch fetch and prelude-once guidance in
  SKILL.md, with curation discipline in data/README.md
- drop 11_pitfalls.md, renumber the trailing pages and spread retrieval
  tags across topics; lexicon keys are page filenames, so the renumbering
  and the new --check rule cannot land in separate commits
2026-07-29 15:45:47 +08:00

546 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TSL FMArray
这一篇只讲 `FMArray` 文档主干能力:怎样构造 `FMArray`、怎样判断类型、怎样和 `Array` 互转、怎样读取尺寸、做基础运算、做多维转置与维度交换、做矩阵连接、参与 `select/mselect`,以及 `insert/delete/update` 语法边界。
## 本篇职责
回答“什么时候该用 `FMArray` 而不是普通 `array`,以及文档明确 `FMArray` 写法有哪些”。
## 核心规则
- `fmarray[...]` 可以直接构造 `FMArray` 常量。
- `dataType(v)``FMArray` 返回 `27`
- `dataType(v, 1)` 可以读出 `FMArray` 单元格类型;本页文档类型包括 `0` 整型、`1` 浮点、`20` 64 位整型。
- FMArray 相关函数的参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留 FMArray 行为示例和返回形态边界。
- `ifFmarray(v)` 可直接判断值是否为 `FMArray`
- `mInit``mInitDiag``mRand` 都可直接生成 `FMArray`
- `arrayToFm``matrixToArray` 可在 `Array` / `FMArray` 间互转。
- `msize``mrows``mcols` 都支持 `FMArray`;对三维 `FMArray``msize` 会返回全部维度长度。
- `FMArray` 支持和标量、`FMArray``Array` 做基础算符运算。
- `union2` 支持 `FMArray` / `Array` 混合运算;结果类型跟随左值。
- 对超过二维的 `FMArray`,反引号转置会把全部维度倒置;`mswap` 可只交换指定维度。
- `union` 可做按行连接且不去重,但列结构必须兼容。
- `|``:|` 都可做矩阵并右方(按列连接);在 `FMArray` 上行数不一致时会用 `0` 补齐,并且两者表现一致(普通 `array` 上两者行为不同:`:|` 缺位补 `nil``|` 直接顺接,见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md))。
-`FMArray` 做普通 `select` 不会保留 `FMArray` 类型;`mselect` 也不会返回 `dataType=27`
- `insert into a array(...)``delete from a where ...;``update a set ... where ... end;` 都能作用于 `FMArray`,但三者的收尾形式并不完全相同。
## 可直接照写示例
### 常量构造与类型判断
<!-- tags: 建 FMArray, 高性能数组, 字面量写法 -->
代码块身份:可直接照写示例
```tsl
f1 := fmarray[1, 2, 3];
f2 := fmarray[[1, 2], [3, 4]];
f3 := fmarray[1.0, 2.0, 3.5];
writeLn(dataType(f1));
writeLn(dataType(f1, 1));
writeLn(dataType(f3, 1));
writeLn(ifFmarray(f1));
writeLn(length(f1));
writeLn(f1[0], ',', f1[1], ',', f1[2]);
writeLn(mrows(f2));
writeLn(mcols(f2));
writeLn(f2[0,0], ',', f2[0,1], ',', f2[1,0], ',', f2[1,1]);
```
结果说明:
- `dataType(f1)` 返回 `27`
- `dataType(f1, 1)` 返回 `0`
- `dataType(f3, 1)` 返回 `1`
- `ifFmarray(f1)` 返回 `1`
- `length(f1)` 返回 `3`
- `f1` 的三个元素依次是 `1``2``3`
- `f2` 的行数是 `2`、列数是 `2`
- `f2` 四个单元依次是 `1``2``3``4`
代码块身份:输出片段
```text
27
0
1
1
3
1,2,3
2
2
1,2,3,4
```
### `mInit`、`mInitDiag`、`mRand`
<!-- tags: 初始化 FMArray, 对角阵, 随机矩阵 -->
代码块身份:可直接照写示例
```tsl
fm1 := mInit(5, 3);
fm2 := mInit(array(3, 2), 1L);
fd1 := mInitDiag(3, 3, 1);
fr1 := mRand(2, 3);
writeLn(dataType(fm1, 1));
writeLn(length(fm1));
writeLn(fm1[0], ',', fm1[1], ',', fm1[2], ',', fm1[3], ',', fm1[4]);
writeLn(dataType(fm2, 1));
writeLn(mrows(fm2));
writeLn(mcols(fm2));
writeLn(fd1[0,0], ',', fd1[0,1], ',', fd1[1,0], ',', fd1[1,1], ',', fd1[2,2]);
writeLn(mrows(fr1));
writeLn(mcols(fr1));
```
结果说明:
- `mInit(5, 3)` 生成长度为 `5` 的整型 `FMArray`,五个元素都是 `3`
- `dataType(fm1, 1)` 返回 `0`
- `mInit(array(3, 2), 1L)` 的单元格类型是 `20`
- `fm2` 的行数是 `3`、列数是 `2`
- `mInitDiag(3, 3, 1)``(0,0)``(1,1)``(2,2)``1`,而 `(0,1)``(1,0)``0`
- `mRand(2, 3)` 的行数是 `2`、列数是 `3`
### `arrayToFm`、`matrixToArray` 与单元格类型转换
<!-- tags: 普通数组转 FMArray, 互转, 单元格类型 -->
代码块身份:可直接照写示例
```tsl
a1 := array(1, 2, 3.5);
f1 := arrayToFm(a1, 0);
f2 := arrayToFm(a1, 0.0);
f3 := int64(fmarray[1, 2, 3]);
a2 := matrixToArray(fmarray[[1, 2], [3, 8]]);
writeLn(dataType(f1, 1));
writeLn(f1[0], ',', f1[1], ',', f1[2]);
writeLn(dataType(f2, 1));
writeLn(f2[0], ',', f2[1], ',', f2[2]);
writeLn(dataType(f3, 1));
writeLn(f3[0], ',', f3[1], ',', f3[2]);
writeLn(mrows(a2));
writeLn(mcols(a2));
writeLn(a2[0][0], ',', a2[0][1], ',', a2[1][0], ',', a2[1][1]);
```
结果说明:
- `arrayToFm(a1, 0)` 的单元格类型是 `0`,结果是 `1,2,3`
- `arrayToFm(a1, 0.0)` 的单元格类型是 `1`,结果是 `1,2,3.5`
- `int64(fmarray[1, 2, 3])` 的单元格类型是 `20`
- `matrixToArray(fmarray[[1, 2], [3, 8]])` 返回一个 `2 x 2``Array`,内容是 `(1,2)``(3,8)`
### 尺寸与重构
<!-- tags: FMArray 尺寸, 改形状, reshape, 三维 -->
二维和三维尺寸:
代码块身份:可直接照写示例
```tsl
f3 := fmarray[[[1, 1], [2, 2], [3, 3]], [[2, 2], [3, 3], [4, 4]]];
s := msize(f3);
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
```
结果说明:
- `msize(f3)` 的长度是 `3`
- 三个维度依次是 `2``3``2`
`reshape` 会保持 `FMArray` 类型:
代码块身份:可直接照写示例
```tsl
f1 := fmarray[[1, 2], [3, 4], [5, 5]];
r1 := reshape(f1, 6);
writeLn(dataType(r1));
writeLn(length(r1));
writeLn(r1[0], ',', r1[1], ',', r1[2], ',', r1[3], ',', r1[4], ',', r1[5]);
```
结果说明:
- `dataType(r1)` 仍然是 `27`
- `r1` 的长度是 `6`
- 元素依次是 `1``2``3``4``5``5`
### 标量运算与基础算符
<!-- tags: FMArray 加减乘除, 和数字运算 -->
代码块身份:可直接照写示例
```tsl
f1 := fmarray[1, 2, 3];
f2 := fmarray[2, 3, 4];
a1 := array(2, 3, 4);
s0 := f1 + 1;
s1 := f1 + f2;
s2 := f1 + a1;
writeLn(dataType(s0));
writeLn(s0[0], ',', s0[1], ',', s0[2]);
writeLn(dataType(s1));
writeLn(s1[0], ',', s1[1], ',', s1[2]);
writeLn(dataType(s2));
writeLn(s2[0], ',', s2[1], ',', s2[2]);
```
结果说明:
- `f1 + 1``dataType``27`,结果是 `2,3,4`
- `f1 + f2``dataType``27`,结果是 `3,5,7`
- `f1 + array(2, 3, 4)``dataType` 仍是 `27`,结果也是 `3,5,7`
### `union2` 与左值类型
<!-- tags: FMArray 合并, 左值类型决定结果 -->
代码块身份:可直接照写示例
```tsl
f1 := fmarray[1, 2, 0, 4, 5];
a1 := array(1, 0, 7.2);
u1 := f1 union2 a1;
u2 := a1 union2 f1;
writeLn(dataType(u1));
writeLn(dataType(u1, 1));
writeLn(length(u1));
writeLn(u1[0], ',', u1[1], ',', u1[2], ',', u1[3], ',', u1[4], ',', u1[5]);
writeLn(dataType(u2));
writeLn(length(u2));
writeLn(u2[0], ',', u2[1], ',', u2[2], ',', u2[3], ',', u2[4], ',', u2[5]);
```
结果说明:
- `union2` 的结果 `dataType``27`
- `f1 union2 array(1, 0, 7.2)` 的单元格类型会提升为 `1` 浮点型
- `f1 union2 array(1, 0, 7.2)` 的长度是 `6`,结果是 `1,2,0,4,5,7.2`
- `array(1, 0, 7.2) union2 f1``dataType``5`
- `array(1, 0, 7.2) union2 f1` 的长度也是 `6`,结果是 `1,0,7.2,2,4,5`
### 多维转置与维度交换
<!-- tags: 三维转置, 换维度, 维度倒置 -->
三维 `FMArray` 上,反引号转置会把全部维度倒置:
代码块身份:可直接照写示例
```tsl
f3 := fmarray[[[1], [2]], [[1], [0]], [[3], [-8]]];
t := `f3;
s := msize(t);
writeLn(dataType(t));
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
writeLn(t[0,0,0], ',', t[0,0,1], ',', t[0,0,2], ';', t[0,1,0], ',', t[0,1,1], ',', t[0,1,2]);
```
结果说明:
- 原矩阵尺寸是 `3,2,1`,转置后尺寸是 `1,2,3`
- 结果 `dataType` 仍是 `27`
- 转置后的内容是 `[[[1,1,3],[2,0,-8]]]`
只交换指定维度时,使用 `mswap`
代码块身份:可直接照写示例
```tsl
f3 := fmarray[[[1], [2]], [[1], [0]], [[3], [-8]]];
t := mswap(f3, 0, 1);
s := msize(t);
writeLn(dataType(t));
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
writeLn(t[0,0,0], ',', t[0,1,0], ',', t[0,2,0], ';', t[1,0,0], ',', t[1,1,0], ',', t[1,2,0]);
```
结果说明:
- `mswap(f3, 0, 1)` 后尺寸是 `2,3,1`
- 结果 `dataType` 仍是 `27`
- 结果内容是 `[[[1],[1],[3]],[[2],[0],[-8]]]`
### 矩阵连接 / 矩阵并右方:`union`、`|`、`:|`
<!-- tags: FMArray 拼接, 按列连接, 补零对齐 -->
`union` 会按行拼接,不做去重:
代码块身份:可直接照写示例
```tsl
t1 := fmarray[[1, 2], [3, 4], [5, 5]];
t2 := fmarray[[7, 8]];
u := t1 union t2;
writeLn(dataType(u));
writeLn(mrows(u));
writeLn(mcols(u));
writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1], ';', u[3,0], ',', u[3,1]);
```
结果说明:
- `union` 的结果 `dataType``27`
- `t1 union t2` 的行数是 `4`、列数是 `2`
- 拼接后四行依次是 `(1,2)``(3,4)``(5,5)``(7,8)`
`|``:|` 会执行矩阵并右方,也就是按列拼接:
代码块身份:可直接照写示例
```tsl
t1 := fmarray[[1, 2], [3, 4], [5, 5]];
t2 := fmarray[[3, 4], [7, 8], [6, 9]];
u1 := t1 | t2;
u2 := t1 :| t2;
writeLn(dataType(u1));
writeLn(mrows(u1));
writeLn(mcols(u1));
writeLn(u1[0,0], ',', u1[0,1], ',', u1[0,2], ',', u1[0,3]);
writeLn(u1[1,0], ',', u1[1,1], ',', u1[1,2], ',', u1[1,3]);
writeLn(u1[2,0], ',', u1[2,1], ',', u1[2,2], ',', u1[2,3]);
writeLn(u2[0,0], ',', u2[0,1], ',', u2[0,2], ',', u2[0,3]);
writeLn(u2[1,0], ',', u2[1,1], ',', u2[1,2], ',', u2[1,3]);
writeLn(u2[2,0], ',', u2[2,1], ',', u2[2,2], ',', u2[2,3]);
```
代码块身份:输出片段
```text
27
3
4
1,2,3,4
3,4,7,8
5,5,6,9
1,2,3,4
3,4,7,8
5,5,6,9
```
结果说明:
- `|` 的结果 `dataType``27`
- `t1 | t2``t1 :| t2` 的行数都是 `3`、列数都是 `4`
- 两种写法的结果都依次是 `(1,2,3,4)``(3,4,7,8)``(5,5,6,9)`
行数不一致时,`|``:|``FMArray` 上表现一致,缺失行会用 `0` 补齐。
代码块身份:可直接照写示例
```tsl
m1 := fmarray[[1, 2], [3, 4], [5, 5]] | fmarray[[3, 4]];
m2 := fmarray[[3, 4]] | fmarray[[1, 2], [3, 4], [5, 5]];
writeLn(m1[0,0], ',', m1[0,1], ',', m1[0,2], ',', m1[0,3]);
writeLn(m1[1,0], ',', m1[1,1], ',', m1[1,2], ',', m1[1,3]);
writeLn(m1[2,0], ',', m1[2,1], ',', m1[2,2], ',', m1[2,3]);
writeLn(m2[0,0], ',', m2[0,1], ',', m2[0,2], ',', m2[0,3]);
writeLn(m2[1,0], ',', m2[1,1], ',', m2[1,2], ',', m2[1,3]);
writeLn(m2[2,0], ',', m2[2,1], ',', m2[2,2], ',', m2[2,3]);
```
代码块身份:输出片段
```text
1,2,3,4
3,4,0,0
5,5,0,0
3,4,1,2
0,0,3,4
0,0,5,5
```
- `fmarray[[1, 2], [3, 4], [5, 5]] | fmarray[[3, 4]]` 的结果三行依次是 `(1,2,3,4)``(3,4,0,0)``(5,5,0,0)`
- `fmarray[[3, 4]] | fmarray[[1, 2], [3, 4], [5, 5]]` 的结果三行依次是 `(3,4,1,2)``(0,0,3,4)``(0,0,5,5)`
- 把上面两条里的 `|` 改成 `:|`,结果一致
### 排序
<!-- tags: 排序, 从小到大, 按列排, sortArray -->
一维排序:
代码块身份:可直接照写示例
```tsl
s1 := fmarray[10, 2, -3, 8];
sortArray(s1);
writeLn(s1[0], ',', s1[1], ',', s1[2], ',', s1[3]);
```
结果说明:
- 排序后结果是 `-3,2,8,10`
二维按字段排序:
代码块身份:可直接照写示例
```tsl
f1 := fmarray[[11, 12], [31, 4], [5, 5]];
sortTableByField(f1, 0, 1);
writeLn(f1[0,0], ',', f1[0,1], ';', f1[1,0], ',', f1[1,1], ';', f1[2,0], ',', f1[2,1]);
```
结果说明:
- 排序后依次是 `(5,5)``(11,12)``(31,4)`
### TS-SQL 对 `FMArray` 的支持
<!-- tags: 对 FMArray 做查询, mselect -->
代码块身份:可直接照写示例
```tsl
q1 := select * from fmarray[[1, 2], [0, 4], [1, 2], [5, 6]] end;
q2 := mselect * from fmarray[[1, 2], [0, 4], [1, 2], [5, 6]] end;
writeLn(dataType(q1));
writeLn(mrows(q1));
writeLn(dataType(q2));
writeLn(mrows(q2));
writeLn(mcols(q2));
```
结果说明:
- 普通 `select` 的返回 `dataType``5`
- `q1` 的行数是 `4`
- `mselect` 的返回 `dataType``17`
- `q2` 的行数是 `4`、列数是 `2`
- 说明对 `FMArray` 做 TS-SQL 查询时,结果不会保留 `dataType=27`
### `insert` / `delete` / `update`
<!-- tags: FMArray 增删改, 写回 -->
`insert`
代码块身份:可直接照写示例
```tsl
a := mInit(2, 3, 1.0);
insert into a array(9);
writeLn(mrows(a));
writeLn(mcols(a));
writeLn(a[2,0], ',', a[2,1], ',', a[2,2]);
```
结果说明:
- 插入后行数是 `3`
- 列数仍是 `3`
- 新插入的第三行是 `9,9,9`
`delete`
代码块身份:可直接照写示例
```tsl
d := fmarray[[1, 2], [0, 4], [5, 6]];
delete from d where [1] = 4;
writeLn(mrows(d));
writeLn(d[0,0], ',', d[0,1], ';', d[1,0], ',', d[1,1]);
```
结果说明:
- 删除后行数是 `2`
- 保留的两行是 `(1,2)``(5,6)`
`update`
代码块身份:可直接照写示例
```tsl
u := fmarray[[1, 2], [0, 4], [5, 6]];
update u set [0] = 100 where [1] = 4 end;
writeLn(mrows(u));
writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1]);
```
结果说明:
- 更新后行数仍是 `3`
- 结果三行依次是 `(1,2)``(100,4)``(5,6)`
这三种写法的收尾形式为:
- `insert into a array(9);`
- `delete from d where [1] = 4;`
- `update u set [0] = 100 where [1] = 4 end;`
## 本页不生成的范围
- `mInitDiag` 更高维行为
- `mRand` 的随机分布参数变体
- `union` / `|` / `:|` 与普通 `array` 的更多混合边界
- `left join` / `right join` / 更复杂 SQL 写回
- CopyOnWrite 的内存级行为
这些不作为本页可生成事实。
## 默认生成模板
需要 `FMArray` 常量时,优先从这个最短模板开始:
代码块身份:可直接照写示例
```tsl
f := fmarray[1, 2, 3];
```
## 禁止项
- 在一个 `FMArray` 常量里混用不同单元格类型。
-`FMArray` 当成支持字符串下标的 `array`
- 以为对 `FMArray` 做普通 `select` 后,结果还是 `dataType=27`
-`delete``update` 的结尾形式写成同一种。
- 以为 `union` 可以忽略列结构差异。
- 以为 `array union2 fmarray` 还会返回 `FMArray`
代码块身份:反例 / 不可照写
```text
f := fmarray[1, 2.0, 3];
```
上面这种写法不作为可写事实,会编译失败,错误信息包含 `fmarray must be same type`
代码块身份:反例 / 不可照写
```text
f := fmarray[1, 2, 3];
writeLn(f["A"]);
```
上面这种写法不作为可写事实,会运行报错,错误信息包含 `fmarray index type error`
代码块身份:反例 / 不可照写
```text
delete from d where [1] = 4 end;
```
这类写法不要直接当成默认模板。`delete ... end;` 会报 `Statement missing terminator`;文档明确写法是 `delete ...;`
代码块身份:反例 / 不可照写
```text
t1 := fmarray[[1, 2], [3, 4]];
t2 := fmarray[[7, 8, 9]];
u := t1 union t2;
```
上面这种写法会运行报错,错误信息包含 `union dim dismatch`。本页明确的 `union` 只适用于列结构兼容的 `FMArray`