📝 docs(tsl-syntax-reference): document verified facts from FAQ corpus
从 FAQ 语料(2018 篇镜像)与参考页做完 169 条逐条差集,补入 6 组此前未收录的语言 事实。每条先用 TSL.exe 实跑观察行为,再收敛成 39 条断言的回归门,在 TSLGen2、 AnalyseNG.NET、TSL 三个解释器上均通过后才写入。 - 16 页:0/0 得 nan、2/0 得 inf;nan 的 = > < >= <= 恒假而 <> 为真;nan 沿算术 传播;nil 在乘除减里按 0 参与 - 04 页:整体赋值免声明,但对未建立的变量写单元格赋值会报「变量类型不是Array」 - 07 页:相邻两个 if 是两条独立语句都会执行;for..in 单控制变量拿到的是键不是值; 二维数组按行推进,行本身是数组(新增 syntax-07-013) - 21 页:子矩阵赋值语句求值为 0;t[:,:] 按位置复制不按列名对齐(新增 syntax-21-019);| 列并时同名字符串列键由右操作数覆盖(新增 syntax-21-018) - 13 页:select 输出列表同名列后者覆盖前者,须用 as 改名(新增 syntax-13-032) 三条 FAQ 说法实跑不复现,故未写入:12574 的括号消歧、19857 的 -2147483648 字面量限制、31474 的 :. bugfix 记录。15305/11045 的用户/公用/共享函数同名解析 优先级需要服务端多账号环境,本地无法验证,仍为已知缺口。 lexicon.json 为 16 页补两个页级 alias,使 nan/nil 语义能被自然语言查询命中。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,8 @@
|
||||
- 遍历时需要维度信息可用 `mIndexCount`;需要第 `n` 维下标可用 `mIndex(n)`。
|
||||
- 子矩阵提取可以写 `matrix[row_start:row_end, col_start:col_end]`、`matrix[:, col_range]`、`matrix[row_index_array, col_index_array]`。
|
||||
- 子矩阵赋值可以写成单个标量,也可以写成同结构矩阵;赋值矩阵应和目标子矩阵形状匹配。
|
||||
- 子矩阵赋值语句本身**没有返回值**:`(m[:, "a"] := v)` 求值为 `0`,而普通赋值 `(a := v)` 求值为被赋的值。不要把子矩阵赋值写在需要取值的位置。
|
||||
- `t[:, :] := source` 按**位置**逐单元复制,不按列名对齐。`source` 里若有某行的列存储顺序与其它行不同,复制结果会静默错位;先用 `source[:, array("列1", "列2")]` 统一列序再赋值。
|
||||
- 子矩阵也可以接 `::=` 做逐单元赋值。
|
||||
- `mfind(matrix)` 返回真值单元格下标;一维数组的无条件 `mfind` 返回一维下标数组。
|
||||
- `mfind(matrix, condition)` 返回符合条件的下标行;二维矩阵下每行形如 `array(row_index, col_index)`。
|
||||
@@ -424,6 +426,79 @@ writeLn(matrix_value[1][1]);
|
||||
11
|
||||
```
|
||||
|
||||
### 子矩阵赋值的返回值与对齐方式
|
||||
|
||||
<!-- section-id: syntax-21-019 -->
|
||||
|
||||
<!-- tags: 赋值返回0, 赋值没返回值, 重构数组错位, 按位置复制, 列顺序不一致 -->
|
||||
|
||||
子矩阵赋值不产生返回值,普通赋值才产生:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
source := array(1, 2, 3);
|
||||
plain := (target := source);
|
||||
writeLn("plain:", plain[0]);
|
||||
|
||||
matrix_value := zeros(3, "a");
|
||||
sub := (matrix_value[:, "a"] := source);
|
||||
writeLn("sub:", sub);
|
||||
writeLn("written:", matrix_value[0]["a"]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- `plain` 拿到被赋的数组,所以 `plain[0]` 输出 `1`
|
||||
- `sub` 输出 `0`:子矩阵赋值语句本身求值为 `0`,不是被赋的值
|
||||
- `written` 输出 `1`:赋值本身生效了,只是取不到返回值
|
||||
- 所以 `return m[:, "a"] := v;` 这种写法会返回 `0`,要分成两句写
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
plain:1
|
||||
sub:0
|
||||
written:1
|
||||
```
|
||||
|
||||
`t[:, :] := source` 按位置复制,不按列名对齐:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
source := array("k1": ("p": 651, "v": 637),
|
||||
"k2": ("p": 599, "v": 170),
|
||||
"k3": ("v": 200, "p": 607));
|
||||
target := zeros(mRows(source), mCols(source, 1));
|
||||
target[:, :] := source;
|
||||
writeLn("row3 p:", target[2]["p"]);
|
||||
writeLn("row3 v:", target[2]["v"]);
|
||||
|
||||
ordered := source[:, array("p", "v")];
|
||||
fixed := zeros(mRows(ordered), mCols(ordered, 1));
|
||||
fixed[:, :] := ordered;
|
||||
writeLn("fixed p:", fixed[2]["p"]);
|
||||
writeLn("fixed v:", fixed[2]["v"]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 第三行源数据的列存储顺序是 `v`、`p`,与前两行相反
|
||||
- `row3 p` 输出 `200`、`row3 v` 输出 `607`:两个值互换了,因为复制按位置而不按列名
|
||||
- 前两行看不出问题,所以这种错位不会报错,只会静默出现在个别行
|
||||
- `ordered := source[:, array("p", "v")]` 先统一列序后,`fixed p` 输出 `607`、`fixed v` 输出 `200`,恢复正确
|
||||
- 源数据由多个过程分别写入时,各行列序可能不一致,用 `[:, :]` 重构前先统一列序
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
row3 p:200
|
||||
row3 v:607
|
||||
fixed p:607
|
||||
fixed v:200
|
||||
```
|
||||
|
||||
### `mfind` 与 `mfindSparse`
|
||||
|
||||
<!-- section-id: syntax-21-011 -->
|
||||
@@ -963,6 +1038,44 @@ bar 结果 (1,2):2
|
||||
- 上述差异只适用于普通 `array`;`FMArray` 上 `|` 与 `:|` 行为一致且行数不齐时补 `0`,见 [22_fmarray.md](22_fmarray.md)
|
||||
- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil)
|
||||
|
||||
### 列并遇到同名字符串列键
|
||||
|
||||
<!-- section-id: syntax-21-018 -->
|
||||
|
||||
<!-- tags: 同名列合并, 列被覆盖, 合并后值变了, 相同列名, 列并覆盖 -->
|
||||
|
||||
两侧共有的字符串列键不会并成两列,而是被右操作数覆盖:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
left := ones(3, array("A", "B"));
|
||||
right := zeros(3, array("A", "C"));
|
||||
merged := left | right;
|
||||
writeLn("A:", merged[0]["A"]);
|
||||
writeLn("B:", merged[0]["B"]);
|
||||
writeLn("C:", merged[0]["C"]);
|
||||
|
||||
reversed := right | left;
|
||||
writeLn("reversed A:", reversed[0]["A"]);
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- `A` 输出 `0`:`A` 两侧都有,取右操作数 `right` 的值,`left` 的 `1` 被覆盖
|
||||
- `B` 输出 `1`、`C` 输出 `0`:只在一侧出现的列都原样保留
|
||||
- `reversed A` 输出 `1`:换序后仍是右操作数胜出,说明规则是「右侧覆盖左侧」而非「零值覆盖」
|
||||
- 默认数字列下标不会触发覆盖,只有字符串列键相同才会
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
A:0
|
||||
B:1
|
||||
C:0
|
||||
reversed A:1
|
||||
```
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-21-016 -->
|
||||
@@ -990,6 +1103,9 @@ matrix_value := zeros(2, 3);
|
||||
- 把 `::=` 写成带 `begin ... end` 的语句块。
|
||||
- 用 `::` 期待遍历到任意深度;深度遍历使用 `:.`。
|
||||
- 子矩阵赋值时用形状不匹配的矩阵硬塞。
|
||||
- 把子矩阵赋值写在需要取值的位置,例如 `return m[:, "a"] := v;`;它求值为 `0`。
|
||||
- 用 `t[:, :] := source` 重构下标时,假定它会按列名对齐;它按位置复制。
|
||||
- 期待 `|` 把两侧同名字符串列键并成两列;同名键会被右操作数覆盖。
|
||||
- 把 `union` 的复合赋值写成 `union=`;正确写法是 `&=`。
|
||||
- 一维数组直接 `union` 期待得到二维结果;需要先对它连用两次转置前缀(双转置)变成行向量。
|
||||
- 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`。
|
||||
|
||||
Reference in New Issue
Block a user