f_tensor

Macro f_tensor 

Source
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 再将原先包装的维度解包

§References