#list #comprehension #haskell #macro

list_comprehension

Rust 中的类似 Haskell 的列表推导宏

6 个版本

0.2.0 2023 年 11 月 29 日
0.1.5 2023 年 7 月 4 日
0.1.3 2023 年 6 月 29 日

#735Rust 模式

MIT 许可证

19KB
487

列表推导

Rust 中的类似 Haskell 的列表推导宏

语法

ListComprehensionExp:
    comp![ Exp , Qual1 , . . . , Qualn ]  (list comprehension, n ≥ 1 )
  | comp![ Exp ; Qual1 , . . . , Qualn ]  (list comprehension, n ≥ 1 )
  | comp![ Exp => Qual1 , . . . , Qualn ] (list comprehension, n ≥ 1 )
  | lazy_comp![ Exp , Qual1 , . . . , Qualn ]  (lazy list comprehension, n ≥ 1 )
  | lazy_comp![ Exp ; Qual1 , . . . , Qualn ]  (lazy list comprehension, n ≥ 1 )
  | lazy_comp![ Exp => Qual1 , . . . , Qualn ] (lazy list comprehension, n ≥ 1 )

Qual:
    Ident <- Exp            (generator)
  | (for)? Pattern in Exp   (generator[2])
  | let Decl                (local declaration)
  | let DeclWithElse        (local declaration)
  | let (mut)? Decls        (local declaration[1])
  | Exp(bool)               (boolean guard)
 
Decls:
    { Decl1 ; . . . ; Decln }     (n ≥ 0)
    
Decl:
    (mut)? Ident ( : Type )? = Exp
  | Pat = Exp ( , else { ... } )?

DeclWithElse:
   Pat = Exp else { ... }
  
  
[1] if `mut` is used, then all declarations will be added with `mut` unless pattern matching is used
[2] Since parsing the `Pattern in Exp` syntax and the `Exp` (boolean guard) syntax can be ambiguous,
    you can now force the `Pattern in Exp` syntax by prefixing the `Pattern` with `for`

示例

fn main() {
    // example 1
    let arr1: Vec<i32> = comp![n; n in [0, 1, 2, 3], n != 3];
    assert_eq!(arr1, [0, 1, 2]);
    
    // expand the macro:
    let arr1: Vec<i32> = {
        let mut res = Vec::new();
        for n in [0, 1, 2, 3] {
            if !(n != 3) {
                continue;
            }
            res.push(n);
        }
        res
    };

// ----------------------------------------------------------------------------------------------------

    // example 2
    let a = [0, 1, 2];
    let arr2: Vec<(i32, i32)> = comp![
        (n, m)
        , n in a
        , m in [0, 1, 2]
        , n != 2
        , m != 2
    ];
    assert_eq!(arr2, [(0, 0), (0, 1), (1, 0), (1, 1)]);
    
    // expand the macro:
    let arr2: Vec<(i32, i32)> = {
        let mut res = Vec::new();
        for n in a {
            for m in [0, 1, 2] {
                if !(n != 2) {
                    continue;
                }
                if !(m != 2) {
                    continue;
                }
                res.push((n, m));
            }
        }
        res
    };

// ----------------------------------------------------------------------------------------------------
    
    // example 3
    let arr3 = lazy_comp![
        { println!("{i}"); i } 
        , i in 0..3
    ];
    
    for _ in arr3 {
        println!("------")
    }
  
    // console output:
    // 0
    // ------
    // 1
    // ------
    // 2
    // ------
  
    // You can see more examples in tests/test_comp.rs
}

更新

  • v0.2.0
    • 添加了支持懒计算的 lazy_comp 宏,其语法与 comp! 相同。
  • v0.1.5
    • 支持原始的 let else 语法,但不能在 let { ... } 语法中使用。
    • 现在您可以通过在 Pattern in Exp 语法前加 for 来强制使用 Pattern(详细信息请参阅语法)。
  • v0.1.4
    • 允许在局部声明中使用 pattern matching 和不同的 let else
    • 进行了一些优化。
    • 纠正了 README 中的少量错误。

依赖项

~25KB