competitive/tools/
mlambda.rs

1/// Macro that define closure like macro. Unlike closure, this macro localizes variable capture.
2///
3/// # Example
4/// ```
5/// # use competitive::mlambda;
6/// let graph: Vec<Vec<usize>> = vec![vec![1, 2], vec![2], vec![]];
7/// let mut deq = std::collections::VecDeque::new();
8/// let mut dist: Vec<usize> = vec![!0; 3];
9/// mlambda!(
10///     fn push(v: usize, cost: usize) {
11///         if dist[v] > cost {
12///             dist[v] = cost;
13///             deq.push_back(v);
14///         }
15///     }
16/// );
17/// push!(0, 0);
18/// while let Some(v) = deq.pop_front() {
19///     for &to in &graph[v] {
20///         push!(to, dist[v] + 1);
21///     }
22/// }
23/// assert_eq!(vec![0, 1, 1], dist);
24/// ```
25#[macro_export]
26macro_rules! mlambda {
27    (
28        @def ($dol:tt) [$([$x:ident])*][$([$y:ident, $($z:tt)*])*]
29        fn $name:ident($($args:tt)*) -> $ret:ty $body:block
30    ) => {
31        macro_rules! $name {
32            ($($dol $x:expr),* $dol(,)?) => {{
33                $(let $y $($z)* = $dol $y;)*
34                $body
35            }}
36        }
37    };
38    (@pre () [$($x:tt)*][$($y:tt)*] fn $name:ident($($args:tt)*) -> $ret:ty $body:block) => {
39        $crate::mlambda!(@def ($) [$($x)*][$($y)*] fn $name($($args)*) -> $ret $body)
40    };
41    (@pre () [$($x:tt)*][$($y:tt)*] fn $name:ident($($args:tt)*) $body:block) => {
42        $crate::mlambda!(@pre () [$($x)*][$($y)*] fn $name($($args)*) -> () $body)
43    };
44    (@pre ($arg:ident $(:$ty:ty)?) [$($x:tt)*][$($y:tt)*] $($rest:tt)*) => {
45        $crate::mlambda!(@pre () [$($x)* [$arg]][$($y)* [$arg, $(:$ty)?]] $($rest)*)
46    };
47    (@pre ($arg:ident $(:$ty:ty)?, $($args:tt)*) [$($x:tt)*][$($y:tt)*] $($rest:tt)*) => {
48        $crate::mlambda!(@pre ($($args)*) [$($x)* [$arg]][$($y)* [$arg, $(:$ty)?]] $($rest)*)
49    };
50    (fn $name:ident($($args:tt)*) $($rest:tt)*) => {
51        $crate::mlambda!(@pre ($($args)*) [][] fn $name($($args)*) $($rest)*)
52    };
53}