macro_rules! f_tensor {
[
// 要被调用的函数(标识符)
$($path:ident).+;
// 参数的表达式序列
$($($arg:expr $(,)?)+);+ $(;)?
] => { ... };
[
// 要被调用的函数(标识符序列)
$($path:ident).+
// 参数的表达式序列
$( [ $($arg:expr $(,)? )+ ] )+
] => { ... };
[
// 内部标识符
@inner
// 要被调用的函数(已作`[fn]`包装,此处解包)
[ $($f:tt)+ ]
// 只有一个表达式序列
[ $($arg:expr,)+ ]
] => { ... };
[
// 内部标识符
@inner
// 要被调用的函数(已作`[fn]`包装)
$f:tt
// 表达式序列
$args:tt
// 空括号
[]
] => { ... };
[
// 内部标识符
@inner
// 要被调用的函数(已作`[fn]`包装)
$f:tt
// 表达式序列(此处延迟解包,留给后边的`append`)
$args_head:tt
// [[参数头...] 其它参数...]
[ [ $($x:expr,)+ ], $($tail:tt)* ]
] => { ... };
[
// 内部标识符
@inner_expand
// 要被调用的函数(已作`[fn]`包装)
$f:tt
// 表达式序列(此处延迟解包,留给后边的`append`)
$args_head:tt
// 提取的x序列(预备展开)
[ $($x:expr,)+ ]
// (其它参数...)
$other_args:tt
] => { ... };
[
// 内部标识符
@inner_append
// 要被调用的函数(已作`[fn]`包装)
$f:tt
// 表达式序列(此处解包)
[ $($arg_head:expr,)* ]
// 提取的x
[ $x:expr ]
// (其它参数...)
$other_args:tt
] => { ... };
}Expand description
更通用的「函数参数张量展开」宏
- 🎯用于最终版简化一系列「笛卡尔积式组合调用」
- 🚩【2024-03-09 15:01:24】与「函数参数矩阵展开」宏合并
- 📌后者(矩阵)可看作「二维张量」
- ⚠️对「内部转换」
@inner的规定性约束:- 🚩统一使用方括号,避免「圆括号→表达式值」的歧义
- 🚩统一使用逗号分隔(强制尾后逗号),避免「连续圆括号→函数调用」的歧义
§Example
use nar_dev_utils::f_tensor;
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn add3(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
// fallback情况
let m = f_tensor!(@inner [add] [1, 2,]);
assert_eq!(m, 3);
// fallback情况 2
let m = f_tensor!(@inner [add] [1, 2,] []);
assert_eq!(m, 3);
// 正常情况
let m1 = f_tensor![add [1 2] [3 4 5]];
let m2 = f_tensor![add3; 1 2; 3 4; 5 6];
// 📌↓此处对「括号表达式」可用逗号明确分隔,以避免「函数调用」歧义
let m3 = f_tensor![add3 [(2-1), (1+1)] [3 4] [5 6]];
assert_eq!(m1, [[4, 5, 6], [5, 6, 7]]);
assert_eq!(
m2,
// ↓展开结果
[
[[1 + 3 + 5, 1 + 3 + 6], [1 + 4 + 5, 1 + 4 + 6]],
[[2 + 3 + 5, 2 + 3 + 6], [2 + 4 + 5, 2 + 4 + 6]],
]
);
// ↓计算结果
assert_eq!(m3, [[[9, 10], [10, 11]], [[10, 11], [11, 12]],]);§Experiences
- 📝使用「前缀特殊标识符」控制宏匹配时的分派路径
- 💭此举特别像Julia的多分派系统
- 📝涉及「嵌套笛卡尔积展开」时,把其它变量都变成一个维度,在一次调用中只展开一个维度
- 🚩源自GitHub Issue的方法
- 1 先使用「数组」之类的包装成一个令牌树(tt)
- 2 展开另一个维度
- 3 再将原先包装的维度解包
- 🚩源自GitHub Issue的方法